版权声明:本文为博主原创文章,转载需注明出处。 http://blog.csdn.net/qq_29517037
适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式UML图
1.对象适配器模式
我们一定要能看懂UML图,并可以根据UML图写出代码:
public interface Target{
public void Request();
}
public class Adapter implementTarget{
private Adaptee adaptee = new Adaptee();
@Override
public void Request(){
adaptee.SpecificRequest();
}
}
public class Adaptee {
public void SpecificRequest(){
System.out.println("The special request");
}
}
public void main(String[] args){
Target target = new Adapter();
target.Request();
}
2.类适配器模式
上述这种适配器实现方式称作对象适配器模式,我们通过在适配器类中引入需要适配类的对象来达到适配的目的,这是较为常用的一种。另外还有一种类适配器模式代码如下:
public interface Target{
public void Request();
}
public class Adapter extends Adaptee implements Target{
@Override
public void Request(){
SpecificRequest();
}
}
public class Adaptee {
public void SpecificRequest(){
System.out.println("The special request");
}
}
public void main(String[] args){
Target target = new Adapter();
target.Request();
}
其实不管是类适配器还是对象适配器模式,实现的目标是一致的,但是注意,我们之前总结过的合成/聚合复用原则:尽量使用合成/聚合,尽量不要使用类继承。合成和聚合都是关联的特殊种类。聚合表示一种弱的‘拥有’关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分(就像大雁和雁群的关系);合成则是一种强的‘拥有’关系,体现了严格的部分与整体的关系,部分和整体的生命周期一样(比如大雁和翅膀)。 无论是在灵活性还是从我们的设计原则上去考虑我们都应该尽量使用聚合的方案即对象适配器的模式而不是类适配器模式。再次就不再针对适配器模式进行具体的举例。
3.接口适配器模式
另外有别于以上两种的适配器模式我们称之为接口适配器模式。当存在这样一个接口,其中定义了N多的方法,而我们现在却只想使用其中的一个到几个方法,如果我们直接实现接口,那么我们要对所有的方法进行实现,哪怕我们仅仅是对不需要的方法进行置空(只写一对大括号,不做具体方法实现)也会导致这个类变得臃肿,调用也不方便,这时我们可以使用一个抽象类作为中间件,即适配器,用这个抽象类实现接口,而在抽象类中所有的方法都进行置空,那么我们在创建抽象类的继承类,而且重写我们需要使用的那几个方法即可。
public interface A {
void a();
void b();
void c();
void d();
void e();
void f();
}
public abstract class Adapter implements A {
public void a(){}
public void b(){}
public void c(){}
public void d(){}
public void e(){}
public void f(){}
}
public class Ashili extends Adapter {
public void a(){
System.out.println("实现A方法被调用");
}
public void d(){
System.out.println("实现d方法被调用");
}
}
public class Clienter {
public static void main(String[] args) {
A a = new Ashili();
a.a();
a.d();
}
}
4.适配器模式与装饰模式的区分
是否有同学有过这种感觉,觉得对象适配器模式和装饰模式很像,出彩的设计点都是通过聚合实现的。从表面上看区别就是对于装饰模式客户端并不知情,对于适配器模式客户端是知情的,需要改变成实例化适配器类。定义上:
装饰模式:对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。使用原来被装饰的类的一个子类的实例,把客户端的调用委派到被装饰类。
适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。
从定义上看装饰模式是对核心对象或者功能的扩展,适配器模式是把对象或者功能放到一个新对象中引用。举个例子,现在书城卖道德经的书,有线装版,有精装版,有日文版,有英文版,其中线装版和精装版就是装饰模式,日文版和英文版就是适配器模式,各种版本都是为迎合不同消费者的不同需求。为什么呢?因为线装版和精装版的道德经虽然包装不同,但内容相同,日文版和英文版就不同,这两个版本的内容就可能和原版的不同,文化差异嘛,翻译的内容虽来自道德经,但根据不同国家的文化,思维逻辑什么的就可能改变一些想法。
使用条件:
装饰模式一般在下列情况使用:需要扩展一个类的功能或者给你个类增加附加责任;需要动态的给一个对象增加功能,这些功能可以再动态的撤销;需要增加有一些基本功能的排列组合而产生非常大量的功能,从而使得继承关系变得不现实。
适配器模式一般使用的情况包括:系统需要使用现有的类,但此类已经不符合系统的需要;
想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的的类一起工作。适配器模式在系统升级的时候使用的频率很高,对旧系统的一些功能方法在新系统中引用。
Java中的应用:
装饰模式和适配器模式在java中的I/O文件的操作中都有体现。
Java的IO库中处理流的类有FIleInputStream,FileOutputStream,DataInputStream,DataOutputStream类等。在InputStream,OutputStream,Reader,Writer结构的内部,有一些流处理器可以对另一些流处理器起到装饰作用,形成新的,改善的流处理器。这就体现了装饰模式的作用。同时在一些流处理器的内部有对其他流处理器的功能的适配引用,这体现了适配器模式的优点。
5.应用场景
类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,二者主要用于如下场景:
(1)想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
(2)我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。
以上两个场景其实就是从两个角度来描述一类问题,那就是要访问的方法不在合适的接口里,一个从接口出发(被访问),一个从访问出发(主动访问)。
接口适配器使用场景:
(1)想要使用接口中的某个或某些方法,但是接口中有太多方法,我们要使用时必须实现接口并实现其中的所有方法,可以使用抽象类来实现接口,并不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想用的方法的方式来实现。这个抽象类就是适配器。