一、外观模式的定义
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
外观模式让我想起了一套设备,不知道大家有没有照过大头贴,我是没有照过,但是我见过照大头贴的设备。其是由电脑,打印机,白炽灯,相机组成,基本的操作是:打开电脑,打印机,白炽灯,相机设备,然后按一下拍照开关,接着点击打印,照片就出来了,最终关闭所有装置。
各个设备要去单独的打开,拍完照,又要单独去关闭,显然不是很方便。其实如果有一个开关能控制所有设备的开关,那么就能省下好多步骤,就可以大大的提高生产率了。
二、外观模式例子
其实这个就和我们的外观模式相一致,我们可以定义为这套设备定义统一的接口,接口中的方法包括打开,拍照,打印,关闭,在使用外观模式之前,直接在客户端调用每个设备的开关,以及其他的操作,直接将客户端和各个设备耦合在了一起。由于代码比较简单,在此不作演示,下面就只演示使用外观模式的例子。
1 class Program
2 {
3 static void Main(string[] args)
4 {
5
6 ITakePicture takephoto =new TakePicture();
7 takephoto.Open();
8 takephoto.TakePictures();
9 takephoto.Printing();
10 takephoto.Close();
11 Console.ReadKey();
12 }
13 }
14
15 public class Computer
16 {
17 public void Open()
18 {
19 Console.WriteLine("电脑开了");
20 }
21 public void Close()
22 {
23 Console.WriteLine("电脑已经关闭了");
24 }
25 }
26
27 public class Light
28 {
29 public void Open()
30 {
31 Console.WriteLine("灯开了");
32 }
33 public void Close()
34 {
35 Console.WriteLine("灯关闭了");
36 }
37 }
38
39 public class Print
40 {
41 public void Open()
42 {
43 Console.WriteLine("打印机打开了");
44 }
45 public void Printing()
46 {
47 Console.WriteLine("打印完成");
48 }
49 public void Close()
50 {
51 Console.WriteLine("打印机已关闭");
52 }
53 }
54
55 public class Cinema
56 {
57 public void Open()
58 {
59 Console.WriteLine("照相机打开了");
60 }
61 public void Close()
62 {
63 Console.WriteLine("照相机已关闭");
64 }
65 public void TakePictures()
66 {
67 Console.WriteLine("已经拍完了");
68 }
69 }
70
71 public interface ITakePicture
72 {
73 voidOpen();
74 voidTakePictures();
75 voidPrinting();
76 voidClose();
77 }
78
79 public class TakePicture : ITakePicture
80 {
81 Computer computer = new Computer();
82 Light light = new Light();
83 Print print = new Print();
84 Cinema cinema = new Cinema();
85 publicTakePicture()
86 {
87
88 }
89 public void Open()
90 {
91 light.Open();
92 computer.Open();
93 print.Open();
94 cinema.Open();
95 }
96
97 public void TakePictures()
98 {
99 cinema.TakePictures();
100 }
101
102 public void Printing()
103 {
104 print.Printing();
105 }
106
107 public void Close()
108 {
109 light.Close();
110 computer.Close();
111 print.Close();
112 cinema.Close();
113 }
114 }
输出结果:
可以看出外观模式的好处是:简化了设备的接口,同时降低了客户端和各个设备的耦合。例如,照相机的照相方法改成了TakePhoto(),那么也只需要在外观的实现方法中修改该设备的方法即可,不用去修改客户端代码。
三、外观模式需要注意的地方
外观封装了子设备的类,那么客户端是如何调用子设备的方法的?
通过上面的代码可以看出,对于每一个单独的设备的方法的调用我们也是将设备的方法封装到了外观类中(如cinema的takepicture方法被封装在外观类的一个方法中),这里使用了一个原则:
最少知识原则:只和你的密友谈话。
客户端只和外观谈话,不和子设备,如相机,电脑等谈话,降低了客户端和设备的耦合度。
下面给出最少知识原则的指导思想:
就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:
1.该对象本身
2.被当做方法的参数而传过来的对象
3.该方法所创建或实例化的任何对象
4.对象的任何组件
尽管我们有时可以在客户端使用takephoto.print.Printing();但是最好也不要使用,因为客户端这样不仅耦合了TakePhoto类还耦合了Print。所以尽可能自己封装子设备的方法,以便减少客户端和子设备的耦合。
四、适配器、外观、装饰者模式对比
在介绍装饰者模式时,引出了一个开闭原则,即对修改关闭,对扩展开放。装饰者模式主要强调的是在不改变原有类的基础上,添加新功能。
适配器模式,主要是对适配对象进行调整,以便适合消费者的需求。从而达到消费者和被适配者解耦的目的。
外观模式的特点主要是简化接口,以及减少客户端对外观组件的耦合。因为如果客户端变化来,组件的子系统变化了,不用影响客户端。除此之外,在封装组件时,适当的在外观类中添加一些自己想要的规则。如上面例子中各设备的开关顺序,或者拍照和打印之前其设备是否开启等。