使用var + basic依赖工厂比C#接口更松散耦合吗?

时间:2012-09-19 21:06:19

标签: c# oop dynamic interface var

这是一个一般性的设计问题。我们经常使用接口来解耦组件,写入接口而不是实现等。有时使用基本注入技术的接口,例如,

interface IMyInterface
{
    void DoSomething();
}

static class IMyInterfaceFactory
{
    public static IMyInterface GetInstance()
    {
        return new MyInterfaceInstance();
    }
}

class IMyInterfaceConsumer
{
    IMyInterface mInterface;

    public IMyInterfaceConsumer()
    {
        this.mInterface = IMyInterfaceFactory.GetInstance();
    }

    public void UseTheInterface()
    {
        this.mInterface.DoSomething();
    }
}

我的问题是关于使用var关键字。甚至没有使用真正的C#界面,但仍然在设计意义上创建一个“界面”

static class IMyInterfaceFactory
{
    // of course, this doesnt need to be a single instance
    static MyInterfaceInstance mSingleInstance; 

    // no longer programming to the interface, just returning the instance
    public static MyInterfaceInstance GetInstance()
    {
        // null coalesce
        return mSingleInstance ?? (mSingleInstance = new MyInterfaceInstance());
    }
}

class IMyInterfaceConsumer
{
    public void UseTheInterface()
    {
        // shorthand way, could also omit var, too 
        var myInterface = IMyInterfaceFactory.GetInstance();
        myInterface.DoSomething();
    }
}

这样我仍然只需要更改一次工厂,只要它返回的实例支持需要消耗的方法,它就可以工作。然而,优点是生产和消费对象甚至不需要知道任何显式接口,也不存在。它还可以通过多种方法干净地支持接口(防止膨胀的接口声明)。

一个明显的缺点是,每次你想要从'interface'使用一个方法时,工厂可能不得不重新实例化该类,除非有一个缓存的单个实例(如上所述)或使用了一些memoization技术。

这种方法的优点/缺点?这是一种常见做法吗?

2 个答案:

答案 0 :(得分:5)

var关键字没有任何动态或松散的内容。它在编译时触发静态类型推断。

您的第二段代码与

的行为相同
public void UseTheInterface()
{
    // shorthand way, could also omit var, too 
    MyInterfaceInstance myInterface = IMyInterfaceFactory.GetInstance();
    myInterface.DoSomething();
}

工厂功能仍然是强类型的。实际上,通过删除界面,您可以使消费者代码更加紧密耦合。

答案 1 :(得分:1)

Var关键字在技术上仍然是强类型的,因此您的代码确实知道它是什么类/接口。如果你打算将它转储到一个对象中,那么我们就会说你的其余代码都不知道那个工厂会发生什么。我不会建议,但因为那会导致你投射该对象以利用其中的任何东西。

我不确定你在尝试使用“防止膨胀的接口声明”,但你也可以通过扩展基类或抽象类来实现多态性。这样就可以使子类之间通用的任何代码都可以保留,并且可以覆盖每个子类的任何特定代码(方法或属性)。

如果您希望一起更改界面,则需要在界面see this post中实现界面。所以你基本上会让接口A只有方法DoStuff(),并且可以像你描述的那样以多态方式使用从这个接口继承的其他接口。

interface A
{

DoStuff();
}

interface B : A
{
DoSomethingElse();
}

class C : B
{

DoStuff(){}
DoSomethingElse(){}
}

顺便说一句,上面的“单实例缓存”代码接近称为单例pattern的内容。