从我所读到的最佳实践是基于接口的类和松散地耦合对象,以帮助代码重用和单元测试.
这是正确的,是否应该始终遵循规则?
我问的原因是我最近在一个系统中使用了100个非常不同的对象.一些共享的公共接口,但大多数都没有,并想知道它是否应该有一个镜像镜像这些类中的每个属性和函数?
我正在使用C#和dot net 2.0,但我相信这个问题适合多种语言.
它对真正提供服务的对象很有用 - 身份验证,存储等.对于没有任何进一步依赖的简单类型,以及永远不会有任何替代实现的情况,我认为使用具体类型是可以的.
如果你过度使用这种东西,你最终会花费大量时间来嘲笑/抄袭世界上的所有东西 - 这往往最终会造成脆弱的测试.
并不是的.服务组件(为您的应用程序执行操作的类)非常适合接口,但作为一项规则,我不打算为基本实体类提供接口.
例如:如果您正在处理域模型,那么该模型不应该是接口.但是,如果该域模型想要调用服务类(如数据访问,操作系统函数等),那么您应该查看这些组件的接口.这减少了类之间的耦合,意味着它是接口或耦合的"契约".
在这种情况下,您开始发现编写单元测试更容易(因为您可以使用存根/模拟/伪造数据库访问等)并且可以使用IoC交换组件而无需重新编译应用程序.
我只使用需要这种抽象级别的接口 - 即你需要使用多态行为.常见的例子是依赖注入,或者你在某个地方有工厂类型的场景,或者你需要建立一个"多重继承"类型的行为.
在我的情况下,凭借我的开发风格,这种情况经常发生(我赞成在UI控件以外的大多数事情上使用深度继承层次结构进行聚合),但我看到使用非常少的非常好的应用程序.这一切都取决于......
哦,是的,如果你真的大量使用接口 - 当心网络服务.如果需要通过Web服务公开对象方法,则它们无法真正返回或接受接口类型,只能使用具体类型(除非您要手动编写所有自己的序列化/反序列化).是的,这让我感到非常痛苦......
接口的缺点是它们无法进行版本控制.一旦您发布了界面,您将不会对其进行更改.如果您使用抽象类,那么您可以通过添加新方法并将它们标记为虚拟来轻松地扩展合同.
例如,.NET中的所有流对象都派生自System.IO.Stream,它是一个抽象类.这使Microsoft可以轻松添加新功能.在frameworkj的第2版中,他们添加了ReadTimeout和WriteTimeout属性,而不会破坏任何代码.如果他们使用了一个接口(比如IStream),那么他们就无法做到这一点.相反,他们必须创建一个新接口来定义超时方法,如果我们想要使用该功能,我们必须编写代码以有条件地转换为此接口.