【问题标题】:Dependency Injection: Difference between loose coupling mechanisms based on interface and class?依赖注入:基于接口和类的松耦合机制的区别?
【发布时间】:2015-08-30 20:59:39
【问题描述】:
假设,我有 2 个配置。
第一个:
interface I {
...
}
class A implements I {
...
}
class B implements I {
...
}
class Component {
I i;
Component (I i) {
this.i = i;
}
}
第二个:
class C {
...
}
class A extends C {
...
}
class B extends C {
...
}
class Component {
C c;
Component (C c) {
this.c = c;
}
}
这两种配置使用两种不同的松耦合机制(基于接口和基于类)有什么区别?
为什么我需要使用接口而不是类?
【问题讨论】:
标签:
java
dependency-injection
loose-coupling
【解决方案1】:
主要是,使用类是一种更繁重的方法。基类通常包含具体(非抽象)方法。如果你从它们派生,你还需要继承这些你可能不想要的具体方法。
例如,假设您想从 decorator pattern 这样的组合设计模式中受益。在这里,您的装饰器还需要从基类派生并继承具体方法。但是,您的装饰器不需要具体的方法来运行。
总而言之,如果您的抽象是基于类的,那么进行对象组合会更加困难/不干净。
另一方面,通过接口进行抽象并不强制实现类继承任何具体的方法实现。因此,它更干净。
【解决方案2】:
一个对象可以实现多个接口但只能扩展一个类,因此有时松耦合库的用户可能无法扩展您的类。
当你扩展时,你将超类的代码合并到你的代码中,有时没有代码可以合并,所以实现更适合。
最后它不是同一个范式,当你写“B extends A”时,你会说“我是 A,我做同样的事情,但我也可以做其他事情”。当您写“B 实现 A”时,您会说“我是 B,但您可以将我视为 A”。
长话短说,唯一的实际原因是第一个。
【解决方案3】:
基于接口的层次结构是一种很好的设计方法,因为它简化了实现:您总是可以实现一个接口,但并不总是可以扩展一个类(例如,最终类)。或者,另一方面,类的作者并不总是希望它被扩展。
所以,您对在类上使用接口非常感兴趣,因为通过这种方式,您可以接受更广泛的实现。例如:
使用类:
class Component
{
AbstractList c;
Component (AbstractList c){...}
}
...Component 将接受 ArrayList 或 Vector。
相反,使用接口:
class Component
{
List c;
Component (List c){...}
}
...Component 将能够接受 ArrayList、Vector、CopyOnWriteArrayList...