首页 > 代码库 > 适配器模式--Adapter Pattern

适配器模式--Adapter Pattern

  模拟场景:很多人都喜欢看NBA吧,姚明进驻NBA,打开了中国的市场。虽然后面姚明在NBA打得还不错,但是在刚进入NBA篮坛的时候,并不是那么顺利的。语言交流就是一个最大的问题。刚开始打球期间,教练及队员的战术部署姚明都无法理解,所以他需要这么一个翻译者,将教练及队员的意思转达给姚明,这样才可以进行合作。

  现在进行场景的模拟,先不考虑那么多。假如姚明一开始进入NBA的时候就已经会英语,可以进行交流了。那么这个时候教练就可以进行战术的部署了。

  转换成类,所有的队员都要服从教练的战术要求,假设现在教练都要给队员部署进攻和防守的指令。所有大家接收的动作是一致的,只是实现不一样而已。所有这里需要先定义出一个接口或者抽象类。

IPlayer 

 1 package com.zqz.dp.adapter;
 2 /**
 3  * @author Qin 所有运动员的父接口,完成同样的动作
 4  */
 5 public interface IPlayer {
 6     /**
 7      * 运动员进攻
 8      */
 9     void attack();
10     /**
11      * 运动员防守
12      */
13     void defense();
14 }

  构建完接口之后,就是对接口进行实现了。假设现在有前锋forwards、中锋center、后卫guards三种运动员,来根据教练的指令完成不同的动作。

Forwards

 1 package com.zqz.dp.adapter;
 2 /**
 3  * @author Qin
 4  * 前锋类,实现运动员接口,实现自己的动作
 5  */
 6 public class Forwards implements IPlayer {
 7     private String name;    //定义运动员的名字
 8     public Forwards(String name) {        //构造方法赋值
 9         this.name = name;
10     }
11     @Override
12     public void attack() {
13         System.out.println("前锋〖"+this.name+"〗攻击。。。");
14     }
15     @Override
16     public void defense() {
17         System.out.println("前锋〖"+this.name+"〗防守。。。");
18     }
19 }

Center

 1 package com.zqz.dp.adapter;
 2 /**
 3  * @author Qin
 4  * 中锋类,实现运动员接口,实现自己的动作
 5  */
 6 public class Center implements IPlayer {
 7     private String name;    //定义运动员的名字
 8     public Center(String name) {        //构造方法赋值
 9         this.name = name;
10     }
11     @Override
12     public void attack() {
13         System.out.println("中锋〖"+this.name+"〗攻击。。。");
14     }
15     @Override
16     public void defense() {
17         System.out.println("中锋〖"+this.name+"〗防守。。。");
18     }
19 }

Guards

 1 package com.zqz.dp.adapter;
 2 /**
 3  * @author Qin
 4  * 后卫类,实现运动员接口,实现自己的动作
 5  */
 6 public class Guards implements IPlayer {
 7     private String name;    //定义运动员的名字
 8     public Guards(String name) {        //构造方法赋值
 9         this.name = name;
10     }
11     @Override
12     public void attack() {
13         System.out.println("后卫〖"+this.name+"〗攻击。。。");
14     }
15     @Override
16     public void defense() {
17         System.out.println("后卫〖"+this.name+"〗防守。。。");
18     }
19 }

Client

 1 package com.zqz.dp.adapter;
 2 /**
 3  * @author 
 4  * Qin 场景类,模拟NBA比赛
 5  */
 6 public class Client {
 7     public static void main(String[] args) {
 8         IPlayer ba=new Forwards("巴蒂尔");
 9         ba.attack();
10         IPlayer yao=new Center("姚明");
11         yao.attack();
12         yao.defense();
13         IPlayer mai=new Guards("麦迪");
14         mai.defense();
15     }
16 }

  以上的操作很简单,说白了就是父类引用指向子类实例,但是现在姚明是直接可以听懂了教练的战术安排了,这个已经是后面发展得很好的姚明了。并不是一开始不能进行交流的那个大姚了。

  要模拟刚入NBA的大姚,那么说明需要创建一个新的类来表示大姚这个对象。在这里我们把Center改成foreignCenter,表示外籍中锋。而很明显这个时候大姚根本无法听懂教练的意思,所以需要一个翻译者translator,翻译者是可以听懂教练的意思的,但是听懂了总不能自己上场比赛吧,所以要把教练的意思传递给大姚,交给大姚去执行。

  转化为类之间的关系也就是translator类要实现IPlayer接口,并且要有一个fireignCenter的引用,具体的实现交给引用去调用自己的方法。

ForeignCenter

 1 package com.zqz.dp.adapter;
 2 /**
 3  * @author Qin 
 4  * 外籍中锋类,外籍中锋是新引进的类,并不能听懂教练的意思,所以只能执行自己的功能
 5  */
 6 public class ForeignCenter {
 7     private String name; // 定义运动员的名字
 8     public ForeignCenter(String name) { // 构造方法赋值
 9         this.name = name;
10     }
11     public void attack() {
12         System.out.println("外籍中锋〖" + this.name + "〗攻击。。。");
13     }
14     public void defense() {
15         System.out.println("外籍中锋〖" + this.name + "〗防守。。。");
16     }
17 }

Translator

 1 package com.zqz.dp.adapter;
 2 /**
 3  * @author Qin
 4  * 翻译者类,适配器对象。传递教练的意思给外籍中锋
 5  */
 6 public class Translator implements IPlayer {
 7     private ForeignCenter fc;
 8     public Translator() {    //翻译者类知道要把消息传递给谁,所以立即生成外籍中锋实例
 9         fc=new ForeignCenter("大姚");
10     }
11     @Override
12     public void attack() {
13         this.fc.attack();    //告诉大姚要进行攻击
14     }
15     @Override
16     public void defense() {
17         this.fc.defense();    //告诉大姚进行防守
18     }
19 }

  其他类不变。这样就完成了功能,由翻译者转达大姚进行战术的安排。

  上面的操作其实很简单,只是在执行的时候调用的是具体真实类的操作而已。是否会觉得有点跟代理类似,其实会这样觉得是因为我把ForeignCenter中的方法定义成和IPlayer的方法一致。也就是说虽然教练给大姚下达了战术的安排,但是大姚可以执意按自己的想法进行安排。所以这也是和代理不同的地方。

  以上的操作就是适配器模式,准确来说是对象适配器,因为在类中传递了另一个类的引用。还有另一种叫做类适配器。要实现类适配器就方便多了,只要让Translator继承ForeignCenter即可,再调用父类的方法。很明显在这里是不合适的,因为两者不存在is-a的关系,所以在真正开发中,对象适配器用的必类适配器多。

  听名字大家就应该能明白意思了,何为适配器?就是把两个不合适的对象通过一个中间对象连接起来。像我们平常的电池充电不也需要一个电源适配器吗?就是一样的道理。

  适配器模式是一个补救的模式,也就是说一般在开发前期不会考虑该模式,而是在后期扩展中才会考虑到。还是以上面的例子为例,NBA事先根本就不能料想到是否会有中国球员参加比赛,所以才会有翻译者的存在,翻译者就是一个适配器。

适配模式的优点:

  1、  适配器可以将两个毫无关联的对象连接起来。

  2、  增加了类的透明度:也就是说教练根本不用管大姚,直接告诉翻译者如何做就行了。

  3、  提高了类的复用性,易扩展,灵活性好。

适配器的使用场景:

  你有动机去修改一个已经投入生产的接口时,就可以使用适配器进行扩展。

适配器的拓展:

  除了类适配器和对象适配器外,还有一种缺省适配器,所谓的缺省适配器就是说在一个接口中存在了一大堆的方法,但是我们在具体的实现中根本就不需要这么多方法,那么我们就可以创建一个中间类,把这些方法全部空实现,然后具体的类再继承该空实现的类,完成自己所需要的功能。