适配器模式定义:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
适配器模式有三种实现方式:类适配器、对象适配器、接口适配器。类适配器由多继承实现,所以针对Java就不可能了,而对象适配器由接口(多组合)实现,所以可扩展性也比较高。
类适配器,以类给到,在Adapter里,就是将src当做类,继承,
对象适配器,以对象给到,在Adapter里,将src作为一个对象,持有。
接口适配器,以接口给到,在Adapter里,将src作为一个接口,实现。
类适配器:
对象适配器:
被适配者接口Duck:
1 public interface Duck { 2 public void quack(); 3 public void fly(); 4 }
具体的实现被适配者:
1 public class MallardDuck implements Duck { 2 public void quack() { 3 System.out.println("Quack"); 4 } 5 6 public void fly() { 7 System.out.println("I'm flying"); 8 } 9 }
客户看到的目标接口:
1 public interface Turkey { 2 public void gobble(); 3 public void fly(); 4 }
适配器组合被适配者,实现目标接口:
1 public class DuckAdapter implements Turkey { 2 Duck duck; 3 Random rand; 4 5 public DuckAdapter(Duck duck) { 6 this.duck = duck; 7 rand = new Random(); 8 } 9 10 public void gobble() { 11 duck.quack(); 12 } 13 14 public void fly() { 15 if (rand.nextInt(5) == 0) { 16 duck.fly(); 17 } 18 } 19 }
测试类:
1 public class TurkeyTestDrive { 2 public static void main(String[] args) { 3 MallardDuck duck = new MallardDuck(); 4 Turkey duckAdapter = new DuckAdapter(duck); 5 6 for(int i=0;i<10;i++) { 7 System.out.println("The DuckAdapter says..."); 8 duckAdapter.gobble(); 9 duckAdapter.fly(); 10 } 11 } 12 }
适配器模式的优点:
1)将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
2)增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
3)灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
适配器模式的缺点:
1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
适配器模式应用场景
类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,二者主要用于如下场景:
(1)想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
(2)我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。
接口适配器使用场景:
(1)想要使用接口中的某个或某些方法,但是接口中有太多方法,我们要使用时必须实现接口并实现其中的所有方法,可以使用抽象类来实现接口,并不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想用的方法的方式来实现。这个抽象类就是适配器。
外观模式定义:提供了一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层接口,让子系统更容易使用。
原则:最少知识原则---只和你的密友谈话。
电影院外观:
1 public class HomeTheaterFacade { 2 Amplifier amp; 3 Tuner tuner; 4 DvdPlayer dvd; 5 CdPlayer cd; 6 TheaterLights lights; 7 Screen screen; 8 PopcornPopper popper; 9 10 public HomeTheaterFacade(Amplifier amp, 11 Tuner tuner, 12 DvdPlayer dvd, 13 CdPlayer cd, 14 Screen screen, 15 TheaterLights lights, 16 PopcornPopper popper) { 17 18 this.amp = amp; 19 this.tuner = tuner; 20 this.dvd = dvd; 21 this.cd = cd; 22 this.screen = screen; 23 this.lights = lights; 24 this.popper = popper; 25 } 26 27 public void watchMovie(String movie) { 28 System.out.println("Get ready to watch a movie..."); 29 popper.on(); 30 popper.pop(); 31 lights.dim(10); 32 screen.down(); 33 amp.on(); 34 amp.setDvd(dvd); 35 amp.setSurroundSound(); 36 amp.setVolume(5); 37 dvd.on(); 38 dvd.play(movie); 39 } 40 41 42 public void endMovie() { 43 System.out.println("Shutting movie theater down..."); 44 popper.off(); 45 lights.on(); 46 screen.up(); 47 amp.off(); 48 dvd.stop(); 49 dvd.eject(); 50 dvd.off(); 51 } 52 53 public void listenToCd(String cdTitle) { 54 System.out.println("Get ready for an audiopile experence..."); 55 lights.on(); 56 amp.on(); 57 amp.setVolume(5); 58 amp.setCd(cd); 59 amp.setStereoSound(); 60 cd.on(); 61 cd.play(cdTitle); 62 } 63 64 public void endCd() { 65 System.out.println("Shutting down CD..."); 66 amp.off(); 67 amp.setCd(cd); 68 cd.eject(); 69 cd.off(); 70 } 71 72 public void listenToRadio(double frequency) { 73 System.out.println("Tuning in the airwaves..."); 74 tuner.on(); 75 tuner.setFrequency(frequency); 76 amp.on(); 77 amp.setVolume(5); 78 amp.setTuner(tuner); 79 } 80 81 public void endRadio() { 82 System.out.println("Shutting down the tuner..."); 83 tuner.off(); 84 amp.off(); 85 } 86 }
测试类:
1 public class HomeTheaterTestDrive { 2 public static void main(String[] args) { 3 Amplifier amp = new Amplifier("Top-O-Line Amplifier"); 4 Tuner tuner = new Tuner("Top-O-Line AM/FM Tuner", amp); 5 DvdPlayer dvd = new DvdPlayer("Top-O-Line DVD Player", amp); 6 CdPlayer cd = new CdPlayer("Top-O-Line CD Player", amp); 7 TheaterLights lights = new TheaterLights("Theater Ceiling Lights"); 8 Screen screen = new Screen("Theater Screen"); 9 PopcornPopper popper = new PopcornPopper("Popcorn Popper"); 10 11 HomeTheaterFacade homeTheater = 12 new HomeTheaterFacade(amp, tuner, dvd, cd, 13 screen, lights, popper); 14 15 homeTheater.watchMovie("Raiders of the Lost Ark"); 16 homeTheater.endMovie(); 17 } 18 }
结果: