1 基本介绍
外观模式是使用频率非常高的结构式设计模式。定义如下:为子系统中一组接口提供一个统一的入口,外部与其内部的通信通过一个统一的外观类进行。
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 栗子
开发一个可应用于多个软件的文件加密模块,该模块可以对文件中的数据进行加密并将加密之后的数据存储在一个新文件中,具体的流程包括三个部分,分别是读取源文件、加密、保存加密之后的文件,其中,读取文件和保存文件使用流来实现,加密操作通过求模运算实现。
代码如下
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 优化
如何在不修改客户端代码的前提下使用新的外观类呢?解决方法之一是:引入一个抽象外观类,客户端针对抽象外观类编程,而在运行时再确定具体外观类
4 总结
优缺点分析
优点:
- 对客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易
- 实现了子系统与客户端之间的松耦合关系,这使得子系统的变化不会影响到调用它的客户端,只需要调整外观类即可
- 一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
缺点
- 不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性
- 如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则
适用场景