我想知道下面的代码是否显示了一个不好的做法(关于接口继承):
public interface IFoo : IDisposable
{
void Test();
}
public class TestImpl : IFoo
{
public void Test()
{
// do something
}
public void Dispose()
{
// disposing my dependencies
}
}
public class FooFactory
{
public IFoo CreateFoo()
{
return new TestImpl();
}
}
public class Client
{
public void Main()
{
FooFactory factory = new FooFactory();
using(IFoo foo = factory.CreateFoo())
{
// do stuff then auto-dispose
foo.Test();
}
}
}
在这里,我想要两件事: 1.使用C#的using语句,这样我就可以优雅地处理我的具体对象的依赖项(不需要向IDisposable投射任何东西)。 2.使用工厂方法创建具体对象,因此我只能使用接口。
分开,两者都是已知的良好做法,但在一起?我在http://msdn.microsoft.com/en-us/library/ms229022.aspx(MSDN - 接口设计)找不到任何说错的东西,但我认为听起来不错......
我将不胜感激任何评论。如果这是一个不好的做法,我会遇到什么样的问题?
谢谢!
答案 0 :(得分:17)
在野外,没有绝对好或坏的做法,每个都有其优点和缺点。
只有当应用于具体问题时,练习才会变得好或坏(读作:不是IFoo
)。
public bool IsGood<TContext>(IPractice practice)
where TContext : RealWorldApplication, new();
因此,不要试图在MSDN上找到指导,而是问自己以下问题:
这是否解决了问题和使代码更容易阅读?
如果答案是是,请使用它。
就个人而言,我喜欢这种方法。如果IFoo
的合同需要正确处理(请注意:IGraphicalObject
,IResource
,IConnection
),那么这是一个非常好的设计决策明确的。
不要被教条困住:使用接口编程可以减少对具体实现的依赖,但使用接口编程 可能是一场噩梦。合理,就是这样。
您可以使用Google查找从.NET Framework本身的IDisposable
继承的所有接口:
intitle:interface "inherits idisposable" site:msdn.microsoft.com
正如我上面所说,这通常是为已知以消耗资源的实体完成的,例如数据库连接,非托管对象包装器,图形对象等等。
对无处理的类强制执行Dispose()
将是一个坏主意。
在这种情况下,最好将其保留为可选项并检查IDisposable
支持,为suggested by Peter。
答案 1 :(得分:10)
这完全有效。这正是接口的用途。他们定义合同。可以使用多个子合同构建合同。
答案 2 :(得分:3)
我认为这是正确的。您的工厂隐藏了实际实例化的类,因此IFoo
必须继承IDisposable
,以便客户端能够调用Dispose()
。通过这个类,客户端可以 - 而且应该 - 完全不知道实例化的实例类。所有相关信息都应由界面携带 - 包括处置的必要性。
答案 3 :(得分:2)
从技术上讲,这个解决方案一切都很好。
从语义的角度来看,你可以说IDisposable
的需要是一个实现细节,与你班级的实际合同无关。
您可以做的是将对象投放到IDisposable
并仅调用Dispose()
,如果它实现了IDisposable
:
var disposable = foo as IDisposable;
if (disposable != null)
disposable.Dispose();
但在这种情况下,我会按照你的建议继续使用接口继承。它不是最干净的方法,但能完美地完成工作并且需要更少的代码。