著名的设计模式“四人帮”这样评价适配器模式:
将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口(这里的接口不是interface,是广义的接口)不兼容而不能一起工作的那些类可以一起工作。——Gang of Four
主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。
首先,我们来看看类的适配器模式,先看类图:核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口时Targetable,通过Adapter类,将Source的功能扩展到Targetable里,看代码:
public class Source {
public void method1() {System.out.println("this is original method!");
}
}
/* 与原类中的方法相同 */
public void method1();
/* 新类的方法 */
public void method2();
}
public class Adapter extends Source implements Targetable {
@Overridepublic void method2() {
System.out.println("this is the targetable method!");
}
}
测试类:
public class AdapterTest {
public static void main(String[] args) {Targetable target = new Adapter();
target.method1();
target.method2();
}
}
输出:this is original method!this is the targetable method!这样Targetable接口的实现类就具有了Source类的功能(如何让A类使用B 类的功能??)。对象的适配器模式基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。看图: 只需要修改Adapter类的源码即可:
public class Wrapper implements Targetable {
private Source source;public Wrapper(Source source){
super();
this.source = source;
}
@Override
public void method2() {
System.out.println("this is the targetable method!");
}
@Override
public void method1() {
source.method1();
}
}
测试类:public class AdapterTest {
public static void main(String[] args) {
Source source = new Source();
Targetable target = new Wrapper(source);
target.method1();
target.method2();
}
}
输出与第一种一样,只是适配的方法不同而已。
第三种适配器模式是接口的适配器模式,接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。看一下类图:这个很好理解,在实际开发中,我们也常会遇到(例如java.gui.里面的mouseListener的适配器mouseAdapter就是)这种接口中定义了太多的方法,以致于有时我们在一些实现类中并不是都需要。看代码:
public interface Sourceable {
public void method1();public void method2();
}
抽象类Wrapper2:
public abstract class Wrapper2 implements Sourceable{
public void method1(){}public void method2(){}
}
public class SourceSub1 extends Wrapper2 {
public void method1(){System.out.println("the sourceable interface's first Sub1!");
}
}
public void method2(){
System.out.println("the sourceable interface's second Sub2!");
}
}
public static void main(String[] args) {
Sourceable source1 = new SourceSub1();
Sourceable source2 = new SourceSub2();
source1.method1();
source1.method2();
source2.method1();
source2.method2();
}
}
测试输出:the sourceable interface's first Sub1!the sourceable interface's second Sub2!达到了我们的效果! 讲了这么多,总结一下三种适配器模式的应用场景:类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。
Eg:java.io
ByteArrayInputStream 是一个对象适配器类,它继承了 InputStream 的接口,并且封装了一个 byte 数组。
换言之,它将一个 byte 数组的接口适配成 InputStream 流处理器的接口。
FileInputStream 是一个适配器类。在 FileInputStream 继承了 InputStrem 类型,同时持有一个对 FileDiscriptor 的引用。
这是将一个 FileDiscriptor 对象适配成 InputStrem 类型的对象形式的适配器模式。
Reader 类型的原始流处理器都是适配器模式的应用。StringReader 是一个适配器类,StringReader 类继承了 Reader 类型,持有一个对 String 对象的引用。 它将 String 的接口适配成 Reader 类型的接口。优点
适配器模式也是一种包装模式,它与装饰模式同样具有包装的功能,此外,对象适配器模式还具有委托的意思。总的来说,适配器模式属于补偿模式,专用来在系统后期扩展、修改时使用。
过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
装饰器模式
Decorator模式Decorator模式,顾名思义,就是修饰、装饰、锦上添花的意思。如果一个类已经有一些功能,你如果还想添加一些其他的功能,就可以使用Decorator模式。通过使用Decorator模式,可以在运行时扩充一个类的功能。其原理是:增加一个装饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造器的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。装饰类必须和被装饰的类有相同的接口。因为,实际功能还是由原来的类实现的,装饰器类只是修饰、添加了一些更好看的更方便更高效的功能。
对于Decorator模式,可以这样形同:我们都给老板打工,我们配合做同样的事情,以我作为主,以你与老板联系为主,我做的差不多了,你帮我把把关,美化一下,最后由你想老板汇报。
Eg:java.io.inputstream
运用比喻进行内在化:
就像衣服和人的关系一样。
人是抽象的构件abstract component,mary是具体的构件concrete component。
衣服是抽象的装饰abstract decorator,礼服、制服、便衣、运动服、工作服等等不同种类的衣物是具体的装饰类concrete decorator
不同的场合需要不同的衣服,但是做事的还是mary(具体组件)而不是衣服(具体装饰)。
应用场景:
1、需要扩展一个类的功能。
2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)
缺点:产生过多相似的对象,不易排错!
装饰模式一般在下列情况使用:需要扩展一个类的功能或者给你个类增加附加责任;需要动态的给一个对象增加功能,这些功能可以再动态的撤销;需要增加有一些基本功能的排列组合而产生非常大量的功能,从而使得继承关系变得不现实。
适配器模式一般使用的情况包括:系统需要使用现有的类,但此类已经不符合系统的需要;想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的的类一起工作。适配器模式在系统升级的时候使用的频率很高,对旧系统的一些功能方法在新系统中引用。
模式概念的出现,完善到合理应用是前辈们在实际的应用中不断总结的结晶。对于不同的需求合理的使用模式能起到事半功倍的效果,但是模式不是放之四海而皆准的,况且模式也不是一成不变死板的,随着技术的发展,工程师的智慧总结,可能会有新的模式出现和旧的模式的消亡,模式就是为实际需要而生,没必要上升到哲学这种高度。