设计模式之适配器模式(adapter pattern)

适配器主要用于接口的转换或者将接口不兼容的类对象组合在一起形成对外统一接口,是一种结构性模式,其本质是是一个中间件,适用于类及其对象。
本文希望通过简单的介绍和分析,能让读者对适配器模式有一个简单直观的认识和感知。

1.目的

对现有的类的接口进行转换以符合新的需求。

2.动机

通过转换或者组合,间接复用已有功能模块完成需求。

3.优缺点

优点:

  1. 提高了类的复用;
  2. 组合若干关联对象形成对外提供统一服务的接口;
  3. 扩展性、灵活性好。

缺点:

  1. 过多使用适配模式容易造成代码功能和逻辑意义的混淆。
  2. 部分语言对继承的限制,可能至多只能适配一个适配者类,而且目标类必须是抽象类。

4.分类

  • 类适配器
  • 对象适配器
  • 接口适配器

  本文主要介绍前两者。

5.主要用途及场景

该模式并不是在设计开发阶段考虑的,主要用在想要修改一个已经存在的接口,或者组合若干关联对象的时候。

  1. 想用一个已经存在的类,但其接口不符合需求;
  2. 想创建一个可以复用的类,该类可以与其他不相关的类协同工作;
  3. 想使用一些已经存在的子类,但是不能对每一个都进行子类化以匹配它们的接口(仅适用于对象Adapter)。对象适配器可以适配他的父类接口。

6.原理

下面是GoF介绍的典型的类适配器模式和对象适配器模式的UML类图

类适配器

原理:通过类继承实现适配,继承Target的接口,继承Adaptee的实现

对象适配器

原理:通过类对象组合实现适配

Target:

 定义Client真正需要使用的接口。

Adaptee:

 其中定义了一个已经存在的接口,也是我们需要进行适配的接口。

Adapter:

 对Adaptee和Target的接口进行适配,保证对target中接口的调用可以间接转换为对Adaptee中接口进行调用。

7.实现

接下来先将上面的UML类图转换为两个具体的例子,然后在对每一种类型在使用一个具体例子介绍.
下面我们使用几个例子来实际体验一下代理模式的应用。

7.1 类适配器

定义目标接口类:Target

public interface Target {
    void request();
}

被适配的类:Adaptee

public class Adaptee {
    public void adapteeRequest() {
        System.out.println("adapteeRequest method of Adaptee! ");
    }
}

适配类Adapter,继承Target的接口request,同时继承Adaptee的实现adapteeRequest

public class Adapter extends Adaptee implements Target {
    @Override
    public void request() {
        // TODO Auto-generated method stub
        super.adapteeRequest();
    }
}

演示:

public class Demo {
    public static void main(String [] args) {
        Target target = new Adapter();
        target.request(); // result: adapteeRequest method of Adaptee!
    }
}

7.2 对象适配器

从上面两张UML图中可以清楚的看出两者的区别,对象中Adapter不在继承Adaptee,而是将Adaptee作为一个数据成员组合到类定义中,从而实现对其接口的访问。

public class Adapter implements Target {
    private Adaptee adaptee = new Adaptee();
    @Override
    public void request() {
        // TODO Auto-generated method stub
        adaptee.adapteeRequest();
    }
}

7.3 类适配器实例——排序

考虑到某系统中有对数据排序的需求,下面使用适配器看一下如何复用现有的排序接口(下面的例子仅仅为了演示,接口不具实际意义);

现有排序类:EffectiveVectorSort

public class EffectVectorSort {
    public void vectorSort() {
        System.out.println("vectorSort method of EffectVectorSort! ");
    }
}

系统排序所需的接口类定义:DataSort

public interface DataSort {
    void sort();
}

定义适配器:SortAdapter

public class SortAdapter extends EffectVectorSort implements DataSort {
    @Override
    public void sort() {
        // TODO Auto-generated method stub
        super.vectorSort();
    }
}

演示:

public class Demo {
    public static void main(String [] args) {
        DataSort dataSort = new SortAdapter();
        dataSort.sort(); // vectorSort method of EffectVectorSort!
    }
}

7.4对象适配器实例——排序

如果系统中不仅有对向量Vector的排序,也有对元组Tuple和链表LinkList等高级数据结构的排序,那么显然通过无法通过类适配将每一个排序类的子类都继承。这里便可以用到对象适配。

需要修改7.3中的SortAdapter,同时需要定义高级数据结构的排序类。

高级数据结构排序类接口:AdvanceDataSort

public interface AdvanceDataSort {
    void sort();
}

链表排序类:LinkListSort

public class LinkListSort implements AdvanceDataSort {
    @Override
    public void sort() {
        // TODO Auto-generated method stub
        System.out.println("sort method of LinkListSort!");
    }
}

元组排序类:TupleSort

public class TupleSort implements AdvanceDataSort {
    @Override
    public void sort() {
        // TODO Auto-generated method stub
        System.out.println("sort method of TupleSort");
    }
}

重定义适配器:SortAdapter

public class SortAdapter implements DataSort {
    private EffectVectorSort vectorSort = new EffectVectorSort();
    private AdvanceDataSort listSort = new LinkListSort();
    private AdvanceDataSort tupleSort = new TupleSort();
    @Override
    public void sort(String dataType) {
        // TODO Auto-generated method stub
        if(dataType == "vector") {
            vectorSort.vectorSort();
        }
        else if(dataType == "linklist") {
            listSort.sort();
        }
        else if(dataType == "tuple") {
            tupleSort.sort();
        }
        else {
            System.out.println("Invalid Data Type:" + dataType);
        }
    }
}

演示:

public class Demo {
    public static void main(String [] args) {
        DataSort dataSort = new SortAdapter();
        dataSort.sort("vector");      // vectorSort method of EffectVectorSort!
        dataSort.sort("linklist");    // sort method of LinkListSort!
        dataSort.sort("tuple");       // sort method of TupleSort
        dataSort.sort("dict");        // Invalid Data Type:dict
    }
}

限于篇幅,先介绍到这里。上面的例子都是比较直观,简单的。好好体会,将其应用到实际编程中才是我们的目的。

参考:

GoF《Design Patterns: Elements of Reusable Object-Oriented Software》

https://www.runoob.com/design-pattern/adapter-pattern.html

(0)

相关推荐

  • 通俗易懂系列 | 设计模式(三):适配器模式

    今天看了部特工电影,里面有个桥段,主角在直升机上和反派生死搏斗,而飞机则是无人驾驶的状态,有坠毁的危险.生死存亡,危急时刻主角让团队成员去驾驶,而团队成员很慌张地说:"Hey, man,你开 ...

  • 每天学习一个设计模式(一):结构型之适配器模式

    一.基本概念 适配器模式是将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的的类的兼容性问题. 二.通俗解释 ADAPTER 适配器模式:在朋友聚会上碰到了一个美女Sar ...

  • PHP设计模式之适配器模式

    PHP设计模式之适配器模式 这个模式一直以来都有一个很经典的例子,那就是插座!没错,当我们从国外买回来电器,或者旅游出差去国外的时候,经常会需要一个电源适配器,因为我国的电压标准是220伏,而其他国家 ...

  • PHP设计模式—适配器模式

    定义: 适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口.Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 结构: Target:目标接口,定义与 ...

  • 设计模式之单例模式(Singleton Pattern)

    一.定义 一个类只有一个实例,且该类能自行创建这个实例的一种模式. 二.单例模式举例 例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各 ...

  • [PHP小课堂]PHP设计模式之适配器模式

    [PHP小课堂]PHP设计模式之适配器模式 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[DarkMatterZyCoder/149844827]免费得PHP.项目管理学习资料

  • 【设计模式】单例模式(Singleton Pattern)

    懒汉式 public class Singleton { private static Singleton instance; private Singleton() {}; public stati ...

  • 【转】C#设计模式-单例模式(Singleton Pattern)

    目录 介绍 第一个版本 --不是线程安全的 第二个版本 -- 简单的线程安全 第三个版本 - 使用双重检查锁定尝试线程安全 第四个版本 - 不太懒,不使用锁且线程安全 第五版 - 完全懒惰的实例化 第 ...

  • 设计模式之适配器模式案例详解

    基本介绍 适配器模式将某个类的接口转换成客户端期望的另一个接口表示,主要目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作. 适配器模式属于结构性模式,主要分为三类:类适配器模式.对象适 ...

  • 设计模式之☞适配器模式,通俗易懂,一学就会!!!

    简介 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁.这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能.这种模式涉及到一个单一的类,该类负责加入独立的或不兼容 ...

  • 设计模式 | 适配器模式(adapter)

    定义: 将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作.   书中说到Gof的设计模式中,讲了两种类型的适配器模式: 1.类适配 ...

  • 设计模式(七)——适配器模式(SpringMVC框架分析)

    适配器模式1 现实生活中的适配器例子泰国插座用的是两孔的(欧标),可以买个多功能转换插头 (适配器) ,这样就可以使用了. 2 基本介绍1) 适配器模式(Adapter Pattern)将某个类的接口 ...