Til*_*lak 20 design-patterns adapter
如何决定何时使用对象适配器以及何时使用类适配器?
问题陈述:创建社交网站并提供来自facebook,google plus和orkut的导入功能.我无法决定是使用对象适配器还是类适配器.
我已经看过Adapter Pattern:Class Adapter vs Object Adapter,但无法理解差异的本质.
Mat*_*att 40
主要区别:
类适配器使用继承,只能包装一个类.它无法包装接口,因为根据定义它必须从某个基类派生.
对象适配器使用组合,可以包装类或接口,或两者.它可以这样做,因为它包含作为私有的封装成员,它包装的类或接口对象实例.
差异很微妙.通常后面的方法(有利于组合而不是继承)是优选的,如我在这里引用的链接中所解释的:
面向对象编程(OOP)已经为功能重用提供了众所周知的候选:继承(白盒重用)和组合(黑盒重用).如果您尝试通过从类继承来重用代码,则会使子类依赖于父类.这使得系统在许多情况下不必要地复杂,不太可测试并且使得在运行时的功能交换不必要地变得困难.作为[清洁代码开发人员],当您需要确定继承是否合适时,您应该遵循Liskov替换原则(LSP).
组合意味着一个类使用另一个类.您将通过清楚地定义接口来进一步促进解耦.这也将为您提供可轻松替换实现的优势.因此,在开始应用Liskov Substitution的原则之前,请考虑一下"赞成组合而不是继承"概念,并问你十二,为什么你不应该立即选择组合.
"因为继承将子类暴露给其父实现的细节,所以通常会说'继承会破坏封装'".(Gang of Four 1995:19)
简单来说, 类适配器使用子类和对象适配器使用组合使用委托.
例:
class MyExistingServiceClass {
public void show() {
System.out.println("Inside Service method show()");
}
}
interface ClientInterface {
void display();
}
class MyNewClassAdapter extends MyExistingServiceClass implements ClientInterface {
void display() {
show();
}
}
Run Code Online (Sandbox Code Playgroud)
以上是类适配器的示例.我们通过从display()的内部实现中调用现有的show()方法,将MyExistingServiceClass调整为ClientInterface.
要将其转换为对象适配器,代码将如下所示:
class MyNewObjectAdapter implements ClientInterface {
MyExistingServiceClass existingClassObject;
void display() {
existingClassObject.show();
}
}
Run Code Online (Sandbox Code Playgroud)
现在何时使用Object适配器代替Class Adatper,
当没有办法根据客户端的界面对要调整的类进行子类化时.例如,当MyExistingServiceClass被声明为final时.
当客户期望合同不是接口而是抽象类实现时.在这种情况下,除了子类化客户端的期望类之外别无他法,因为我们不能将多个类子类化,除了使用该类作为组合之外,没有其他方法.
abstract class AbstractClientClass {
abstract void display();
}
class MyNewObjectAdapter extends AbstractClientClass {
MyExistingServiceClass existingClassObject;
void display() {
existingClassObject.show();
}
}
Run Code Online (Sandbox Code Playgroud)当您需要调整多个对象时.这种情况是指您不直接使用对象进行调整.这里一个很好的例子是javax.swing中的JTable类.此类创建一个GUI(图形用户界面)表组件,其中包含适配器提供给它的信息.为了显示域中的数据,JTable提供了接受javax.swing.table中定义的TableModel实例的构造函数.JDK使用AbstractTableModel提供TableModel的现有抽象实现.
class MyTableModel extends AbstractTableModel {
MyDomainObject[] existingDomainObjects[];
public int getColumnCount() {
return 4;
}
public int getRowCount() {
return existingDomainObjects.length();
}
public MyDomainObject getValueAt(int i) {
return existingDomainObjects[i];
}
}
Run Code Online (Sandbox Code Playgroud)在这里,我们调整了MyDomainObject以便与AbstractTableModel一起使用.
对象适配器:
$Adapter = new MyEngine(new MyAdapter($options));
$Adapter->write('something');
Run Code Online (Sandbox Code Playgroud)
类适配器
MyAdapter extends BaseAdapter implements AdapterInterface { ... }
$Adapter = new MyAdapter($options);
$Adapter->write('something');
Run Code Online (Sandbox Code Playgroud)