设计模式--适配器模式
1. 解决的问题
Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。适配器主要的功能是用于代码的复用,而不是实现新的功能;
2. 模式中的角色
目标接口(Target):客户所期待的接口(适配的最终结果)。目标可以是具体的或抽象的类,也可以是接口。
需要适配的类(Adaptee):需要适配的类或适配者类(代码需要被复用的类)。
适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。
--- Target 和 Adaptee 两者间是没有关联的
3.适配器模式的类图
Java中常见的适配器模式的实现方式主要是依靠对象组合的方式实现的(可参加第4部分时序图),原因是:Java只支持单继承;
虽然使用类继承也可能完成适配器模式,但是面向对象的开发中我们应该遵循优先使用组合而不是继承的原则(参见《Effective Java》);
具体的常见实现:
1、适配器 Adapter 通常是一个具体的类,让其实现 Target 接口,在 Adapter 类(具体实现)中去调用 Adaptee ;
2、可以在 Adapter 具体实现类中加入新的功能,这个时候适配器成为“智能适配器”;(和装饰器模式感觉差不多了,后面有解释哦!);
代码实现示例:
// 定义客户端期待的接口
public class Target{
// 使用virtual修饰以便子类可以重写
public virtual void Request(){
System.out.println("This is a common request");
}
}
// 定义需要适配的类
public class Adaptee{
public void SpecificRequest(){
System.out.println("This is a special request.");
}
}
// 定义适配器
public class Adapter:Target{
// 建立一个私有的Adeptee对象
private Adaptee adaptee = new Adaptee();
// 通过重写,表面上调用Request()方法,变成了实际调用SpecificRequest()
public override void Request(){
adaptee.SpecificRequest();
}
}
使用代码示例:
class Program{
static void Main(string[] args){
// 对客户端来说,调用的就是Target的Request()
Target target = new Adapter();
target.Request();
// do something
}
}
4. 适配器模式的调用时序图
5. 模式总结
5.1 优点
1 通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单、更直接、更紧凑。
2 复用了现存的类,解决了现存类和复用环境要求不一致的问题。
3 将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。
4 一个对象适配器可以把多个不同的适配者类适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
5.2 缺点
对于对象适配器来说,更换适配器的实现过程比较复杂。
5.3 适用场景
1 系统需要使用现有的类,而这些类的接口不符合系统的接口。
2 想要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
3 两个类所做的事情相同或相似,但是具有不同接口的时候。
4 旧的系统的类已经实现了一些功能,但是客户端却只能以另外接口的形式访问,但我们不希望手动更改原有类的时候。
5 使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。
6:Java I/O中适配器模式的体现:
Java I/O中Reader和Writer还有InputStreamReader、FileReader和OutputStreamWriter、FileWriter这样4个实现的子类, 而他们和字节流之间的关系采用了适配器这种设计模式。具体分析等下次分析啦!
7、适配器模式、装饰模式、(静态)代理模式的关系。
- 装饰模式 ( Decorator ):是通过对一个已有对象的进一步封装来实现功能上的扩展。这个相对于类扩展继承更为动态化,是基于已有对象而非类的扩展。
- 代理模式 ( Proxy ):也是通过对一个对象的“封装”,“屏蔽”掉client请求对真实原始对象的直接调用。
单纯从类和对象结构上来看,装饰模式、代理模式和适配器模式(尤其是对象的实现方式)大有相似之处。但他们之间也存 在很多不同的地方,使用的场景也不相同。
适配器模式偏重的是适配,即实现要适配的接口功能(也即:复用已有的代码)。
装饰模式偏重的是对已有对象的功能扩展。
代理模式则偏重的是“隐藏真实的对象”(访问逻辑的控制),因此通常这个代理的构建过程是不直接由client控制的。