结构型设计模式 -- 适配器模式
一、小案例分析
1、功能需求:
以电源适配器为例。
一个人去外国旅游,住在外国某宾馆,恰好手机没电(手机是双孔插头),但外国宾馆只有三孔插座,宾馆一般不可能为了旅客,将三孔插座换成双孔插座,此时适配器就派上用场了,将双孔插头转成三孔插头,即可满足要求。
2、什么是适配器模式:
适配器模式是一种结构型设计模式。适配器模式的思想是:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
3、适配器模式分类
(1)类适配器模式
(2)对象适配器模式
(3)接口适配器模式
4、适配器模式的角色:
(1)源(Adaptee):需要被适配的对象或类型,相当于双孔插头。
(2)适配器(Adapter):连接目标和源的中间对象,相当于插头转换器。
(3)目标(Target):期待得到的目标,相当于三孔插头。
二、适配器模式
1、类适配器模式实现案例:
(1)适配器对象继承原有类(比如三孔插头)。
(2)适配器对象组合一个实现新接口的对象(比如双孔插头)。
(3)适配器原有的方法调用被委托给新接口的实例的方法。即在新接口的方法中调用原有类的方法。(使双孔插头可以调用三孔插头)
(4)代码实现:
package adapter.pattern.demo1; /** * 测试类, 测试类适配器模式 */ public class ClassAdapterDemo { public static void main(String[] args) { Adapter adapter = new Adapter(); adapter.show2(); } } /** * 三孔插头(原有类) * */ class ThreeHolePlug { public void show1() { System.out.println("三孔插头"); } } /** * 双孔插头(新需求) */ interface DoubleHolePlug { public void show2(); } /** * 继承原有类,并实现新接口,重写接口中的方法,并调用原有类的方法。 * */ class Adapter extends ThreeHolePlug implements DoubleHolePlug { @Override public void show2() { show1(); } }
(5)代码分析:
采用继承实现,使该类有一定的局限性。但是可以根据需求获取或重写原有类的方法。
(6)UML图:
2、对象适配器模式实现案例
(1)适配器对象内部持有原有类的实例对象。(即三孔插口对象)
(2)适配器对象组合一个实现新接口的对象(比如双孔插头)。
(3)适配器原有的方法调用被委托给新接口的实例的方法。即在新接口的方法中调用原有类的方法。(使双孔插头可以调用三孔插头)
(4)代码实现:
package adapter.pattern.demo2; /** * 测试类, 测试对象适配器模式 */ public class ObjectAdapterDemo { public static void main(String[] args) { Adapter adapter = new Adapter(new ThreeHolePlug()); adapter.show2(); } } /** * 三孔插头(原有类) * */ class ThreeHolePlug { public void show1() { System.out.println("三孔插头"); } } /** * 双孔插头(新需求) */ interface DoubleHolePlug { public void show2(); } /** * 实现新接口,重写接口中的方法,将原有类的的实例化对象放入适配器中,通过实例化对象去调用原有类的方法。 * */ class Adapter implements DoubleHolePlug { ThreeHolePlug threeHolePlug; /** * 构造器,将原有类的实例对象传入适配器 * * @param threeHolePlug * 原有类的实例对象 */ public Adapter(ThreeHolePlug threeHolePlug) { this.threeHolePlug = threeHolePlug; } @Override public void show2() { threeHolePlug.show1(); } }
(5)代码分析:
此段代码,根据合成复用原则,使用聚合的方式代替继承,降低了继承的局限性,且不再要求新需求必须是接口。
(6)UML图:
3、接口适配器模式(缺省适配器模式):
(1)当一个接口中抽象方法过多时,实现这个类需要将所有的方法实现,不友好。可以采用一个抽象类,实现接口、重写所有方法(将其重写为空方法)。此时继承抽象类,并根据需要选择重写的方法即可。
(2)适用于使用一个接口,却不想重写接口中所有方法的情景。
(3)代码实现:
package adapter.pattern.demo3; /** * 测试类, 测试接口适配器模式 */ public class InterfaceAdapterDemo { public static void main(String[] args) { // 根据自己的需求,重写相关方法,不需要全部重写 new MoveApapter() { @Override public void up() { System.out.println("向上移动"); } }.up(); new MoveApapter() { @Override public void down() { System.out.println("向下移动"); } }.down(); } } /** * 接口中含有多个抽象方法 * */ interface Move { void up(); void down(); void left(); void right(); } /** * 抽象类,实现接口,并重写所有的方法为空方法 * */ abstract class MoveApapter implements Move { @Override public void up() { } @Override public void down() { } @Override public void left() { } @Override public void right() { } }
(4)UML图: