适配器模式与外观模式

适配器模式定义:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

适配器模式有三种实现方式:类适配器、对象适配器、接口适配器。类适配器由多继承实现,所以针对Java就不可能了,而对象适配器由接口(多组合)实现,所以可扩展性也比较高。

类适配器,以类给到,在Adapter里,就是将src当做类,继承, 
对象适配器,以对象给到,在Adapter里,将src作为一个对象,持有。 
接口适配器,以接口给到,在Adapter里,将src作为一个接口,实现

类适配器:

对象适配器:

被适配者接口Duck:

1 public interface Duck {
2     public void quack();
3     public void fly();
4 }
View Code

具体的实现被适配者:

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 }
View Code

客户看到的目标接口:

1 public interface Turkey {
2     public void gobble();
3     public void fly();
4 }
View Code

适配器组合被适配者,实现目标接口:

 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 }
View Code

测试类:

 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 }
View Code

适配器模式的优点

1)将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。

2)增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。

3)灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。

类适配器模式还具有如下优点:

由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。

对象适配器模式还具有如下优点:

一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。

适配器模式的缺点

1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。

2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

类适配器模式的缺点如下: 对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。
对象适配器模式的缺点如下: 与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。
 
 

适配器模式应用场景

类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,二者主要用于如下场景:

  (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 }
View Code

测试类:

 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 }
View Code

结果:

猜你喜欢

转载自www.cnblogs.com/cing/p/9168178.html
今日推荐