风格的不同:IDictionary与Dictionary

时间:2009-10-20 15:31:40

标签: c# java .net interface

我有一个朋友刚刚开始使用Java进行.NET开发很长时间了,在查看了他的一些代码后,我注意到他经常做以下事情:

IDictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();

他将字典声明为接口而不是类。通常我会做以下事情:

Dictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();

我只在需要时使用IDictionary接口(例如,将字典传递给接受IDictionary接口的方法)。

我的问题是:他的做事方式有什么好处吗?这是Java中的常见做法吗?

14 个答案:

答案 0 :(得分:59)

如果IDictionary是一个比Dictionary更“通用”的类型,那么在声明变量时使用更通用的类型是有意义的。这样您就不必太在意分配给变量的实现类,并且您可以在将来轻松更改类型,而无需更改大量以下代码。例如,在Java中,通常认为做得更好

List<Integer> intList=new LinkedList<Integer>();

比做

LinkedList<Integer> intList=new LinkedList<Integer>();

这样我确定所有后续代码都将列表视为List而不是LinkedList,这样可以在将来轻松切换LinkedList for Vector或任何其他实现List的类。我会说这对Java来说很常见,而且编程也很好。

答案 1 :(得分:27)

这种做法不仅限于Java。

当你想要从你正在使用的类中解除对象的实例时,它也经常在.NET中使用。如果使用Interface而不是Class,则可以在需要时更改支持类型,而不会破坏其余代码。

您还会看到这种做法在使用工厂模式处理IoC容器和实例化时会大量使用。

答案 2 :(得分:14)

你的朋友正在遵循这个非常有用的原则:

“从实施细节中抽象出来”

答案 3 :(得分:8)

对于已经是实现细节的局部变量和私有字段,最好使用具体类型而不是声明的接口,因为具体类提供了性能提升(直接调度比虚拟/接口调度更快)。如果您没有在本地实现细节中不必要地转换为接口类型,JIT也将能够更容易地内联方法。如果从返回接口的方法返回具体类型的实例,则转换是自动的。

答案 4 :(得分:7)

你应该总是尝试编程到界面而不是具体的类。

使用Java或任何其他面向对象的编程语言。

在.NET中,通常使用I表示这是您正在使用的界面。我认为这更常见,因为在C#中他们没有implementsextends来引用类和接口继承。

我认为乳清会输入

 class MyClass:ISome,Other,IMore 
 { 
 }

您可以告诉ISome IMore是接口而Other是一个类

在Java中不需要这样的东西

 class MyClass extends Other implements Some, More {
 }

这个概念仍然适用,你应该尝试编写接口代码。

答案 5 :(得分:5)

据我所知,Java开发人员倾向于比.NET开发人员更频繁地使用抽象(和设计模式)。这似乎是另一个例子:为什么在他基本上只使用接口成员时声明具体类?

答案 6 :(得分:4)

大多数情况下,您会看到当成员公开外部代码时使用的接口类型(IDictionary),无论是在程序集外部还是在类外部。通常,大多数开发人员在内部使用具体类型来定义类定义,同时使用接口类型公开封装属性。通过这种方式,他们可以利用具体类型的功能,但如果他们更改具体类型,则声明类的接口不需要更改。

public class Widget
{
    private Dictionary<string, string> map = new Dictionary<string, string>();
    public IDictionary<string, string> Map
    {
        get { return map; }
    }
}

以后可以成为:


class SpecialMap<TKey, TValue> : IDictionary<TKey, TValue> { ... }

public class Widget
{
    private SpecialMap<string, string> map = new SpecialMap<string, string>();
    public IDictionary<string, string> Map
    {
        get { return map; }
    }
}

不改变Widget的界面,并且必须更改已经使用它的其他代码。

答案 7 :(得分:3)

在所描述的情况下,几乎每个Java开发人员都会使用该接口来声明变量。 Java集合的使用方式可能是最好的例子之一:

Map map = new HashMap();
List list = new ArrayList();

猜猜它只是在很多情况下完成松耦合。

答案 8 :(得分:3)

Java Collections包含大量实现。因此,我更容易使用

List<String> myList = new ArrayList<String>();

然后将来当我意识到我需要“myList”是线程安全的,只需将这一行更改为

List<String> myList = new Vector<String>();

并且不更改其他代码行。这包括getter / setter。例如,如果你看一下Map的实现数量,你可以想象为什么这可能是一个好习惯。在其他语言中,只有几个实现的东西(对不起,不是一个大的.NET人),但在Objective-C中,实际上只有NSDictionary和NSMutableDictionary。所以,它没有多大意义。

编辑:

无法点击我的一个关键点(只是使用getter / setter提到它)。

以上允许您拥有:

public void setMyList(List<String> myList) {
    this.myList = myList;
}

使用此调用的客户端无需担心底层实现。使用符合List接口的任何对象。

答案 9 :(得分:3)

来自Java世界,我同意“钻石界面程序”的口号是钻进你的。通过编程到接口而不是实现,您可以使您的方法更具可扩展性,以满足未来的需求。

答案 10 :(得分:1)

我发现对于局部变量,无论你使用的是接口还是具体的类,它通常都没什么关系。

与类成员或方法签名不同,如果您决定更改类型,则很少有重构工作,变量在其使用站点之外也不可见。实际上,当您使用var声明本地时,您没有获得接口类型,而是获取类类型(除非您明确地转换为接口)。

但是,在声明方法,类成员或接口时,我认为预先使用接口类型会让您感到非常头疼,而不是将公共API耦合到特定的类类型。

答案 11 :(得分:1)

使用接口意味着以下代码中的“dictionary”可能是IDictionary的任何实现。

Dictionary1 dictionary = new Dictionary1();
dictionary.operation1(); // if operation1 is implemented only in Dictionary1() this will fail for every other implementation

当您隐藏对象的构造时,最好看到:

IDictionary dictionary = DictionaryFactory.getDictionary(...);

答案 12 :(得分:1)

我遇到过与Java开发人员相同的情况。他以相同的方式将集合AND对象实例化到它们的接口。 例如,

IAccount account = new Account();

属性始终作为接口获取/设置。这会导致序列化问题,这可以很好地解释here

答案 13 :(得分:0)

IDictionary是一个接口,Dictionary是一个类。

Dictionary实现IDictionary

这意味着可以用Dictionary实例引用IDictionary实例,并通过Dictionary实例调用大多数IDictionary方法和属性。

强烈建议您尽可能多地使用接口,因为接口抽象了应用程序的模块和程序集,允许多态,这在很多情况和情况下非常普遍和有用,并且允许在不接触的情况下将一个模块替换为另一个模块其他模块。

假设当前程序员编写:

IDictionary<string> dictionary = new Dictionary<string>();

现在dictionary调用Dictionary<string>的方法和属性。

将来数据库的规模将不断扩大,我们发现Dictionary<string>太慢了,因此我们想用Dictionary<string>来代替RedBlackTree<string>,这是更快的方法。 / p>

因此,所有需要做的就是将上述说明替换为:

IDictionary<string> dictionary = new RedBlackTree<string>();

当然,如果RedBlackTree实现了IDictionary,则该应用程序的所有代码都将成功编译,并且您拥有该应用程序的新版本,该应用程序现在的性能比以前的版本更快,更高效。

没有接口,这种替换将更加困难,并且将要求程序员和开发人员更改更多可能导致错误的代码。