对象适配器模式和类适配器模式之间的区别

时间:2012-04-02 14:43:56

标签: design-patterns adapter

如何决定何时使用对象适配器以及何时使用类适配器?

问题陈述: 要创建社交网站并从facebook,google plus和orkut提供导入功能。我无法决定是使用对象适配器还是类适配器。

我看过Adapter Pattern: Class Adapter vs Object Adapter,但无法理解差异的本质。

5 个答案:

答案 0 :(得分:34)

主要区别:

  • 类适配器使用继承,只能包装。它无法包装接口,因为根据定义它必须从某个基类派生。

  • 对象适配器使用组合,可以包装类或接口,或两者兼而有之。它可以这样做,因为它包含作为私有的封装成员,它包装的类或接口对象实例

差异很微妙。通常后面的方法(赞成composition over inheritance)是优选的,正如我在这里引用的链接中所解释的那样:

  

面向对象编程(OOP)有众所周知的候选人   功能重用:继承(白盒重用)和组合   (黑盒重用)。如果您尝试通过从类继承来重用代码   您将使子类依赖于父类。这样做了   在许多情况下,系统不必要地复杂,不太可测试和制造   在运行时交换功能不必要的困难。作为[清洁代码开发人员]   你应该跟随Liskov Substitution Principle (LSP)   需要决定继承是否合适。

     

组合意味着一个类使用另一个类。你会进一步   通过清楚地定义接口来促进解耦。那也是   为您提供可轻松替换实施的优势。所以   在开始应用Liskov Substitution的原则之前,请考虑一下   关于遗产构成的遗产概念和问题   十二,为什么你不应该立刻喜欢作文。

     

“因为继承将子类暴露给其父类的详细信息   实施时,人们经常说'继承中断   封装'“。(Gang of Four 1995:19)

答案 1 :(得分:6)

对象适配器:

$Adapter = new MyEngine(new MyAdapter($options));
$Adapter->write('something');

类适配器

MyAdapter extends BaseAdapter implements AdapterInterface { ... }
$Adapter = new MyAdapter($options);
$Adapter->write('something');

答案 2 :(得分:6)

简单来说, 类适配器使用子类,对象适配器使用合成使用委派。

示例:

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();
    }
}

以上是类适配器的示例。我们通过从display()的内部实现中调用现有的show()方法,将MyExistingServiceClass调整为ClientInterface。

要将其转换为对象适配器,代码将如下:

class MyNewObjectAdapter implements ClientInterface {

    MyExistingServiceClass existingClassObject;

    void display() {
        existingClassObject.show();
    }
} 

现在何时使用Object适配器代替Class Adatper,

  1. 当无法根据客户端界面对要调整的类进行子类化时。例如,当MyExistingServiceClass被声明为final时。

  2. 当客户希望合约不是接口而是抽象类实现时。在这种情况下,除了子类化客户端的预期类之外别无他法,因为我们不能将多个类子类化,除了使用该类作为组合之外没有其他方法。

    abstract class AbstractClientClass {
        abstract void display();
    }
    
    class MyNewObjectAdapter extends AbstractClientClass { 
    
        MyExistingServiceClass existingClassObject;
    
        void display() {
            existingClassObject.show();
        }
    }
    
  3. 当您需要调整多个对象时。这种情况是指您不直接使用对象进行调整。这里一个很好的例子是javax.swing中的JTable类。此类创建一个GUI(图形用户界面)表组件,其中包含适配器提供给它的信息。为了显示域中的数据,JTable提供了接受TableModel实例的构造函数 在javax.swing.table中定义。 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];
    }
    }
    
  4. 在这里,我们调整了MyDomainObject,以便与AbstractTableModel一起使用。

答案 3 :(得分:1)

类适配器使用多重继承来使一个接口适应另一个接口:(取决于您的编程语言:Java& C#不支持多重继承)

enter image description here

对象适配器取决于对象组成:

enter image description here

图像源:设计模式(可重用面向对象软件的元素)一书

答案 4 :(得分:0)

https://www.journaldev.com/1487/adapter-design-pattern-java 适配器设计模式是结构设计模式之一,它的使用使两个不相关的接口可以一起工作。加入这些不相关接口的对象称为适配器。  -双向适配器模式 在实现Adapter模式时,有两种方法-类适配器和对象适配器-但是,这两种方法都会产生相同的结果。

类适配器 –这种形式使用Java继承并扩展了源接口,在我们的例子中是Socket类。 对象适配器 –此表单使用Java组合,并且适配器包含源对象。