概述
适配器模式是结构型设计模式之一,其在不修改原来两个模块代码的情况下,将两个不兼容的类融合在一起,有点像粘合剂,通过转换使得他们能够协作起来,
符合了开闭原则.
关于适配器模式扩展阅读: 适配器模式原理及实例介绍
定义
适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配无法在一起工作的两个类可以在一起工作.
使用场景
- 系统需要使用现有的类,而此类接口不符合系统的需要,即接口不兼容
- 想要建立一个可重复使用的类,用于关联彼此没有太大关联的一些类(包括即将引入的类)
- 需要一个统一的输出接口,而输入端类型不确定.
UML
Adapter
模式的结构图如下.
- Target:目标角色,期待得到的接口.
- Adaptee:适配者角色,被适配的接口.
- Adapter:适配器角色,将源接口转换成目标接口.
分类
适配器模式分为类适配器模式和对象适配器模式,类适配器通过继承,是静态的定义方式.
而对象适配器通过代理,是动态组合的方式。
代码
类适配器
所谓类适配器,指的是适配器Adapter继承我们的被适配者Adaptee,并实现目标接口Target。由于Java中是单继承,所以这个适配器仅仅只能服务于所继承的被适配者Adaptee。代码如下:
被适配者(Adaptee)
package com.bluemsun.classadapter; public class Person { private int id; private String name; /** * person可以现在只能说英语 */ public void sayEnglish(){ System.out.println("Person can say english!"); } /** * 省略setter,getter. */ }
目标接口(Target)
package com.bluemsun.classadapter; /** * 目标要求person可以说英语,法语,日语.但是现在的person仅仅可以说英语 * @author Administrator * */ public interface Target_Person { void sayEnglish(); void sayFrench(); void sayJapanese(); }
适配器(Adapter)
package com.bluemsun.classadapter; /** * 类适配器,因为继承了Person,而Java中只能单继承,所以这个适配器只为person这一个类服务 * 这个适配器就让person类在不修改源码的基础上能实现目标接口所指定的方法 * @author Administrator * */ public class Adapter_Person extends Person implements Target_Person{ @Override public void sayFrench() { System.out.println("Person can say French!"); } @Override public void sayJapanese() { System.out.println("Person can say Japanese!"); } }
客户端(Client)
package com.bluemsun.classadapter; public class Test { public static void main(String[] args) { Target_Person person = new Adapter_Person(); person.sayEnglish(); person.sayFrench(); person.sayJapanese(); } }
上面的几段简单代码演示了类适配器的作用。正如我们开始所言,这个适配器Adapter只能为Person这一个类所服务。这时候你可能会想,要是我所需要适配的类很多,是不是都需要为每一个需要适配的类写一个Adapter?有没有更加灵活的方式呢?答案是:有!就是我们下面所讲的对象适配器。
对象适配器
所谓对象适配器,简单的说就是适配器实现我们的目标接口,但是并不继承需要被适配的类。而是通过在适配器的构造函数中将需要被适配的类传递进来从而进行适配。代码如下:(Target,Adaptee同上)
适配器(Adapter)
package com.bluemsun.objectdapter; import com.bluemsun.classadapter.Person; import com.bluemsun.classadapter.Target_Person; /** * 对象适配器,与类适配器不同的是:对象适配器可以适配多个源到目标 * @author Administrator * */ public class Adapter_Person implements Target_Person{ //仅仅实现目标接口 private Person person; //在构造函数中将Adaptee类Person传递进来 public Adapter_Person(Person person){ this.person = person; } //实现目标接口中的sayEnglish()--调用Adaptee中的sayEnglish() @Override public void sayEnglish() { this.person.sayEnglish(); } //实现接口中的其它方法 @Override public void sayFrench() { System.out.println("person can say French!"); } @Override public void sayJapanese() { System.out.println("person can say Japanese!"); } }
客户端(Client)
package com.bluemsun.objectdapter; import com.bluemsun.classadapter.Person; import com.bluemsun.classadapter.Target_Person; public class Test { public static void main(String[] args) { Target_Person person = new Adapter_Person(new Person()); person.sayEnglish(); person.sayFrench(); person.sayJapanese(); } }
对象适配器可以适配多个带适配的类。只需要你在Adapter的构造方法中传递不同的带适配的类即可。具有灵活性。
适配器的优缺点
类适配器的优点:
1、由于适配器类是适配者类的子类,因此可以再适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
类适配器的缺点:
1、对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为接口,不能为类,其使用有一定的局限性,不能将一个适配者类和他的子类同时适配到目标接口。
对象适配器的优点:
1、把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和他的子类都适配到目标接口。
对象适配器的缺点:
1、与类适配器模式相比,要想置换适配者类的方法就不容易。