适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。实际生活中,比如有一个二孔插座,我现在需要用洗衣机去洗衣服,但是洗衣机插头需要一个三孔插座,二孔插座肯定不适合,这个时候我又不想把原来墙上的二孔插座砸了,换成三孔插座,怎么办了这时候我们去超市买一个插孔转换器就行了,这个插孔转换器就类似一个适配器。这个适配器呢,既有了原来原来插两个头的插头,又增加了插三个头的新功能。
先创建一个二孔插座类:
package com.tl.skyLine.pattern.AdapterPattern; /** * 二孔插座 * Created by tl on 17/3/9. */ public class TwoHole { public void matchTwo() { System.out.println("我能匹配两个头的插头!"); } }再来一个三孔插座接口,既有支持两孔的方法,又有新增的支持三孔的新方法:
package com.tl.skyLine.pattern.AdapterPattern; /** * 三孔插座 * Created by tl on 17/3/9. */ public interface ThreeHole { /* 与原类中的方法相同 */ void matchTwo(); /* 新类的方法 */ void matchThree(); }创建Adapter类继承TwoHole类,实现ThreeHole接口:
package com.tl.skyLine.pattern.AdapterPattern; /** * Created by tl on 17/3/9. */ public class Adapter extends TwoHole implements ThreeHole { @Override public void matchThree() { System.out.println("我能匹配三个头的插头!"); } }用适配器转换一个三孔插座,测试我们的三孔插座的功能:
package com.tl.skyLine.pattern.AdapterPattern; /** * Created by tl on 17/3/9. */ public class AdapterTest { public static void main(String[] args) { ThreeHole threeHole = new Adapter(); threeHole.matchTwo(); threeHole.matchThree(); } }输出:
我能匹配两个头的插头! 我能匹配三个头的插头!这样,我们再不损坏原有的二孔插座基础上扩展了支持三孔的功能能。
基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承TwoHole类,而是持有TwoHole类的实例,以达到解决兼容性的问题。 修改Adapter类:
/** * Created by tl on 17/3/9. */ public class Adapter implements ThreeHole { private TwoHole twoHole; public Adapter(TwoHole twoHole) { this.twoHole = twoHole; } @Override public void matchTwo() { twoHole.matchTwo(); } @Override public void matchThree() { System.out.println("我能匹配三个头的插头!"); } }测试:
/** * Created by tl on 17/3/9. */ public class AdapterTest { public static void main(String[] args) { ThreeHole threeHole = new Adapter(new TwoHole()); threeHole.matchTwo(); threeHole.matchThree(); } }输出:
我能匹配两个头的插头! 我能匹配三个头的插头!输出与第一种一样,只是适配的方法不同而已。
在实际开发中,我们也常会遇到这种接口中定义了太多的方法,以致于有时我们在一些实现类中并不是都需要。但是实现接口就必须重写所有的方法,为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,这样我们就可以选择性的实现我们需要的方法了。 这次有一个插座类:
package com.tl.skyLine.pattern.AdapterPattern; /** * 插座 * Created by tl on 17/3/9. */ public interface Socket { void matchTwo(); void matchThree(); }我们需要创建一个二孔插座类TwoHole,就需要实现Socket(这是插座,不是套接字),但是我们只想实现一个方法,只要支持两个孔就行了,但是java语言规定,你实现一个接口必选实现所有的方法,然后TwoHole就不干了,我是小二,不要小三。。。怎么办呢,这时候增加一个抽象类SocketAdapter作为中间类,实现所有的接口方法,然后TwoHole再继承SocketAdapter就行,
package com.tl.skyLine.pattern.AdapterPattern; /** * Created by tl on 17/3/9. */ public abstract class SocketAdapter implements Socket { @Override public void matchTwo() { } @Override public void matchThree() { } } package com.tl.skyLine.pattern.AdapterPattern; /** * 二孔插座 * Created by tl on 17/3/9. */ public class TwoHole extends SocketAdapter { @Override public void matchTwo() { System.out.println("我能匹配两个头的插头!"); } }测试:
package com.tl.skyLine.pattern.AdapterPattern; /** * Created by tl on 17/3/9. */ public class AdapterTest { public static void main(String[] args) { Socket socket = new TwoHole(); socket.matchTwo(); } }输出:
我能匹配两个头的插头!总结一下三种适配器模式的应用场景:
类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Adapter类,持有原类的一个实例,在Adapter类的方法中,调用实例的方法就行。
接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类SocketAdapter,实现所有方法,我们写别的类的时候,继承抽象类即可。
在此呢,也稍微区别一下装饰模式,代理模式,适配器模式, 概念上区别: 适配器模式,一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。 装饰器模式,原有的不能满足现有的需求,对原有的进行增强。 代理模式,同一个类而去调用另一个类的方法,不对这个方法进行直接操作。 代码上区别: 适配器模式是将一个类(a)通过某种方式转换成另一个类(b)。 装饰模式是在一个原有类(a)的基础之上增加了某些新的功能变成另一个类(b)。 代理模式是将一个类(a)转换成具体的操作类(b)。
真正理解透着这些设计模式,还需要在代码中不断总结,比较!!!