设计模式目录:
概述
第1 部分 问题引入
OO适配器是什么,现实中到处都是。比如:如果你需要在欧洲国家使用美国制造的笔记本电脑,你可能需要使用一个交流电的适配器……
你知道适配器的作用:它位于美式插头和欧式插座的中间,它的工作是将欧式插座转换成美式插座,好让美式插头可以插进这个插座得到电力。或者也可以这么认为:适配器改变了插座的接口,以符合美式笔记本电脑的需求。
好了,这是真实世界的适配器,那面向对象适配器又是什么?其实,OO适配器和真实世界的适配器扮演者同样的角色:将一个接口转换成另一个接口,以符合客户的期望。
下面是一个鸭子接口:
1 /** 2 * 鸭子接口 3 * @ClassName: Duck 4 * TODO 5 * @author Xingle 6 * @date 2014-10-9 下午3:33:04 7 */ 8 public interface Duck { 9 10 public void quack(); 11 public void fly(); 12 13 }
绿头鸭是鸭子的子类:
1 /** 2 * 绿头鸭 3 * @ClassName: MallardDuck 4 * @author Xingle 5 * @date 2014-10-9 下午3:38:54 6 */ 7 public class MallardDuck implements Duck{ 8 9 @Override 10 public void quack() { 11 System.out.println("Quack"); 12 } 13 14 @Override 15 public void fly() { 16 System.out.println("I'm flying."); 17 } 18 19 }
最新的“接头顽禽”——火鸡
1 /** 2 * 火鸡 3 * @ClassName: Turkey 4 * @author Xingle 5 * @date 2014-10-9 下午3:54:37 6 */ 7 public interface Turkey { 8 9 public void gobble(); 10 public void fly(); 11 12 }
火鸡的具体实现:
1 /** 2 * 火鸡的具体实现类 3 * @ClassName: WildTurkey 4 * TODO 5 * @author Xingle 6 * @date 2014-10-9 下午3:55:23 7 */ 8 public class WildTurkey implements Turkey{ 9 10 @Override 11 public void gobble() { 12 System.out.println("Gobble gobble."); 13 } 14 15 @Override 16 public void fly() { 17 System.out.println("I'm flying a short distance."); 18 } 19 20 }
下面,是一个适配器:
1 /** 2 * 鸭子适配器 3 * @ClassName: TurkeyAdapter 4 * TODO 5 * @author Xingle 6 * @date 2014-10-9 下午3:58:12 7 */ 8 public class TurkeyAdapter implements Duck{ 9 10 Turkey turkey; 11 12 public TurkeyAdapter(Turkey turkey){ 13 this.turkey = turkey; 14 } 15 16 @Override 17 public void quack() { 18 turkey.gobble(); 19 } 20 21 @Override 22 public void fly() { 23 for(int i=0;i<5;i++){ 24 turkey.fly(); 25 } 26 27 } 28 29 }
测试程序:
1 /** 2 * 适配器测试程序 3 * @ClassName: TurkeyTestDrive 4 * @author Xingle 5 * @date 2014-10-9 下午4:03:21 6 */ 7 public class TurkeyTestDrive { 8 public static void main(String[] args){ 9 //先创建一个鸭子和一个火鸡 10 MallardDuck duck = new MallardDuck(); 11 WildTurkey turkey = new WildTurkey(); 12 //将火鸡包装进一个火鸡适配器中,使它看起来像是一只鸭子 13 Duck turkeyAdapter = new TurkeyAdapter(turkey); 14 //测试火鸡,让它咯咯叫,让它飞 15 System.out.println("The Turkey says..."); 16 turkey.gobble(); 17 turkey.fly(); 18 19 //先测试鸭子,传入一个鸭子对象 20 System.out.println("\nThe Duck says..."); 21 testDuck(duck); 22 23 //接着测试,传入一个假装是鸭子的火鸡 24 System.out.println("\nThe TurkeyAdapter says..."); 25 testDuck(turkeyAdapter); 26 } 27 28 static void testDuck(Duck duck) { 29 duck.quack(); 30 duck.fly(); 31 } 32 33 }
执行结果:
第2部分 适配器模式定义
适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原来接口不兼容的类可以合作无间。
这个模式可以通过创建适配器进行接口转换,让不兼容的接口变成兼容。这可以让客户从实现的接口解耦。如果在一段时间之后,我们想要改变接口,适配器可以将改变的部分封装起来,客户就不必为了应对不同的接口而每次跟着修改。
现在来看它的类图:
这个适配器模式有着良好的OO设计原则:使用对象组合,以修改的接口包装被适配者:这种做法还有额外的有点,那就是,被适配者的任何子类,都可以搭配着适配者使用。
第3 部分 对象和类的适配者
第4 部分 适配器模式与装饰者模式区别
适配器模式:将一个类的接口,转化成客户期望的另一个接口,适配器让原本接口不兼容的类可以合作无间。
装饰者模式:动态的将责任附加到对象上(因为利用组合而不是继承来实现,而组合是可以在运行时进行随机组合的)。若要扩展功能,装饰者提供了比继承更富有弹性的替代方案(同样地,通过组合可以很好的避免类暴涨,也规避了继承中的子类必须无条件继承父类所有属性的弊端)。
总结:适配器模式主要是为了接口的转换,而装饰者模式关注的是通过组合来动态的为被装饰者注入新的功能或行为(即所谓的责任)。
适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增强新的行为和责任;而外观将一群对象包装起来以简化其接口
第5 部分 外观模式
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
外观和最少知识原则: