结构式:外观模式

1 基本介绍

​ 外观模式是使用频率非常高的结构式设计模式。定义如下:为子系统中一组接口提供一个统一的入口,外部与其内部的通信通过一个统一的外观类进行。

image-20220320141134145

2 代码框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class SubSystemA {
public void MethodA() {
// 业务代码
}
}

class SubSystemB {
public void MethodB() {
// 业务代码
}
}

class SubSystemC {
public void MethodC() {
// 业务代码
}
}

class Facade {
private SubSystemA obj1 = new SubSystemA();
private SubSystemB obj1 = new SubSystemB();
private SubSystemC obj1 = new SubSystemC();

public void Method() {
obj.MethodA();
obj.MethodB();
obj.MethodC();
}
}

class Program {
static void Main(string[] args) {
Facade facade = new Facade(); facade.Method();
}
}

3 设计分析

3.1 栗子

​ 开发一个可应用于多个软件的文件加密模块,该模块可以对文件中的数据进行加密并将加密之后的数据存储在一个新文件中,具体的流程包括三个部分,分别是读取源文件、加密、保存加密之后的文件,其中,读取文件和保存文件使用流来实现,加密操作通过求模运算实现。

image-20220320141855040

​ 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package DesignPatterns.JavaDesign.Facade;

import sun.misc.BASE64Encoder;

import javax.sound.sampled.AudioFormat;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Test {
public static void main(String[] args) {
EncryptFacade ef = new EncryptFacade();
ef.FileEncrypt("src.txt", "des.txt");
}
}

class FileReader {
public String Read(String fileNameSrc)
{
System.out.println("读取文件,获取明文:");
FileInputStream fs = null;
StringBuilder sb = new StringBuilder();
try {
fs = new FileInputStream(fileNameSrc);
int data;
while((data = fs.read())!= -1) {
sb = sb.append((char)data);
}
fs.close();
System.out.println(sb);
}catch(FileNotFoundException e) {
System.out.println("文件不存在!");
}catch(IOException e) {
System.out.println("文件操作错误!");
}
return sb.toString();
}
}

class CipherMachine {
public String Encrypt(String plainText) {
System.out.println("数据加密,将明文转换为密文:");
String es = "";
char[] chars = plainText.toCharArray();
for(char ch: chars) {
String c = String.valueOf(ch % 7); es += c;
}
System.out.println(es);
return es;
}
}

class FileWriter {
public void Write(String encryptStr,String fileNameDes) {
System.out.println("保存密文,写入文件。");
FileOutputStream fs = null;
try {
fs = new FileOutputStream(fileNameDes);
byte[] str = encryptStr.getBytes(StandardCharsets.UTF_8);
fs.write(str,0, str.length);
fs.flush();
fs.close();
}catch(FileNotFoundException e) {
System.out.println("文件不存在!");
}catch(IOException e) {
System.out.println(e.getMessage());
System.out.println("文件操作错误!");
}
}
}

class EncryptFacade {
//维持对其他对象的引用
private FileReader reader;
private CipherMachine cipher;
private FileWriter writer;
public EncryptFacade() {
reader = new FileReader();
cipher = new CipherMachine();
writer = new FileWriter(); }
//调用其他对象的业务方法
public void FileEncrypt(String fileNameSrc, String fileNameDes) {
String plainStr = reader.Read(fileNameSrc);
String encryptStr = cipher.Encrypt(plainStr);
writer.Write(encryptStr, fileNameDes);
}
}

3.2 优化

​ 如何在不修改客户端代码的前提下使用新的外观类呢?解决方法之一是:引入一个抽象外观类,客户端针对抽象外观类编程,而在运行时再确定具体外观类

image-20220320144853344

4 总结

优缺点分析

优点:

  1. 对客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易
  2. 实现了子系统与客户端之间的松耦合关系,这使得子系统的变化不会影响到调用它的客户端,只需要调整外观类即可
  3. 一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。

缺点

  1. 不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性
  2. 如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则

适用场景

  • 当要为访问一系列复杂的子系统提供一个简单入口时可以使用外观模式

  • 客户端程序与多个子系统之间存在很大的依赖性。

  • 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联

    系,而通过外观类建立联系,降低层之间的耦合度


结构式:外观模式
https://2w1nd.github.io/2022/03/15/设计模式/结构式:外观模式/
作者
w1nd
发布于
2022年3月15日
许可协议