外观模式
概述
外观模式是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,使子系统与客户端的耦合度降低,且客户端调用非常方便
自己泡茶和酒馆泡茶的差别
在外观模式中,一个子系统的外部与其内部通信通过一个统一的外观类进行,外观类将客户类与子系统的内部复杂性分隔开来,使得客户类只需要与外观角色大较大,而不需要与子系统内部的很多对象打交道
外观模式: 为子系统中的一组接口提供一个统一的入口,外观模式定义了一个高层接口,整个接口使得这一子系统更加容易使用
外观模式
- Facade(外观角色) 在客户端可以调用它的方法,在外观角色中可以知道(一个或者多个)子系统的功能和责任,在正常情况下,它将所有客户端发来的请求委派到响应的子系统,传递相应的子系统对象处理
- SubSystem(子系统对象) 在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能,每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求,子系统并不知道外观的存在,对于子系统而言,外观角色斤进是另一个客户端而已
/**
*
* @ClassName: CipherMchine
* @Description:数据加密类, 充当子系统类
* @Author Crazy
* @DateTime 2019年11月4日 下午9:19:43
*/
public class CipherMchine {
public String encrypt(String plainText) {
System.out.println("数据加密,将明文转换为密文");
String es = "";
for (int i = 0; i < plainText.length(); i++) {
String c = String.valueOf(plainText.charAt(i)%7);
es += c;
}
System.out.println(es);
return es;
}
}
/**
*
* @ClassName: FileReader
* @Description: 文件读取类,充当子系统
* @Author Crazy
* @DateTime 2019年11月4日 下午9:14:51
*/
public class FileReader {
public String read(String fileNameSrc) {
System.out.println("读取文件,获取明文");
StringBuffer sb = new StringBuffer();
try {
FileInputStream inFS = new FileInputStream(fileNameSrc);
int data;
while((data = inFS.read()) != -1) {
sb = sb.append(data);
}
inFS.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("文件不存在");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("文件操作错误");
}
return sb.toString();
}
}
/**
*
* @ClassName: FileWriter
* @Description: 文件保存类, 充当子系统类
* @Author Crazy
* @DateTime 2019年11月4日 下午9:25:42
*/
public class FileWriter {
public void write(String encryptStr,String fileNameDes) {
// TODO Auto-generated method stub
System.out.println("保存密文,写入文件");
try {
FileOutputStream outFS = new FileOutputStream(fileNameDes);
outFS.write(encryptStr.getBytes());
outFS.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("文件不存在");
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("文件操作错误");
}
}
}
/**
*
* @ClassName: EncryptFacade
* @Description: 加密外观类, 充当外观类
* @Author Crazy
* @DateTime 2019年11月4日 下午9:28:36
*/
public class EncryptFacade {
//维持对子系统对象的引用
private FileReader reader;
private CipherMchine cipher;
private FileWriter writer;
public EncryptFacade() {
// TODO Auto-generated constructor stub
reader = new FileReader();
cipher = new CipherMchine();
writer = new FileWriter();
}
//调用子系统对象的业务方法
public void fileEncrypt(String fileNameSrc,String fileNameDes) {
// TODO Auto-generated method stub
String plainStr = reader.read(fileNameSrc);
String encryptStr = cipher.encrypt(plainStr);
writer.write(encryptStr, fileNameDes);
}
}
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
EncryptFacade ef = new EncryptFacade();
ef.fileEncrypt("src//facadePattern//src.txt", "src//facadePattern//des.txt");
}
}
优缺点
优点
- 他对客户端屏蔽了子系统组件,减少了看客户端所需处理的对象数目, 并使子系统适用起来更加容易,通过引入外观模式,客户端代码将变得更加简单,与之关联的对象也很少
- 它实现了子系统与客户端之间的松耦合关系,使得子系统的变化不会影响调用它的客户端,只需要调整外观类即可
- 一个子系统的修改对其他子系统没有任何影响而且子系统内部变化也不会影响到外观系统
缺点
- 不能很好的限制客户端直接适用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变和灵活性
- 如果设计不当,增加的子系统可能需要修改外观类的源代码,违背了开闭原则
使用环境
- 当要为访问一系类复杂的子系统提供一个简单入口时,可以适用外观模式
- 客户端程序与多个子系统之间存在很大的依赖性,引入外观类可以将子系统与客户端解耦,从而提高子系统的独立性和可移植性
- 在层次化结构中可以适用外观模式定义系统中每一层的入口, 层与层之间不直接残生联系,而通过外观类建立联系,降低层之间的耦合度