外观模式在实际开发中我认为是最简单,最容易实现的一种模式了,有时候我们不知不觉的就用上了,只是我们不知道名字而已,那么我们就来给她立个正名把~
程序运行起来需要编译,链接,运行等步骤,我们创建编译器和链接器
public class Compiler {
public void tokenAnalysis() {
System.out.println("词法分析");
}
public void syntaxAnalysis() {
System.out.println("语法分析");
}
public void makeObjectFile() {
System.out.println("生成目标文件");
}
}
public class Linker {
public void symbolResolution() {
System.out.println("符号决议");
}
public void makeExeFile() {
System.out.println("链接动态库静态库生成可执行文件");
}
public void redirect() {
System.out.println("重定向符号地址");
}
}
客户端代码
public static void main(String[] args) {
System.out.println("编写代码");
Compiler compiler = new Compiler();
compiler.tokenAnalysis();
compiler.syntaxAnalysis();
compiler.makeObjectFile();
Linker linker = new Linker();
linker.symbolResolution();
linker.makeExeFile();
linker.redirect();
}
客户端在这里就相当于我们自己用文本编辑器编写代码,而后自己操作分析代码的词法语法,以及一系列底层编译原理的工作,最后再去执行程序。真实的编译和链接的步骤绝非这么简单,这么庞大和复杂的逻辑步骤不太可能让我们自己去做,所以就有了GCC,g++,等编译器。更高级点的就是IDE,将命令编译和链接的过程都隐藏掉了。我们优化一下代码,在编译器和链接器加上一层
public class IdeTool {
private Compiler compiler = new Compiler();
private Linker linker = new Linker();
public void compile() {
compiler.tokenAnalysis();
compiler.syntaxAnalysis();
compiler.makeObjectFile();
}
public void run() {
linker.symbolResolution();
linker.makeExeFile();
linker.redirect();
}
}
客户端代码
public static void main(String[] args) {
System.out.println("编写代码");
IdeTool ideTool = new IdeTool();
ideTool.compile();
ideTool.run();
}
IDE就相当于一个外观类,它将复杂的编译和链接步骤封装成一系列简单的方法,使我们不需要了解那么多底层的细节。大家看下是不是在自己实际开发中或多或少都用上这个模式了?
在实际的场景中,比如登陆逻辑,可能需要从用户表,权限表中获取和验证数据,此时操作的dao层就是两个。但是上层逻辑是不关注这些组合细节的,而后就有了controller层来做外观类。
这里引出一个原则:迪米特法测 简单来说,就是只和朋友通讯,什么意思呢?如我们上面的第一个例子,客户端直接调用了编译器和链接器,就相当于让我们不太了解底层的同学们去做这个工作,那是多么痛苦的事情,这里就说,客户端与编译器和链接器不是朋友,他们互相不应该直接去建立联系,应该找一个中介去。而中介就是外观类,客户端与中介是朋友,他们两个可以无障碍的沟通。迪米特法测的初衷是让类与类之间的关系变得松耦合,就向我们上班一样,比如公司老板需要向某部门某员工传达一些信息,他一般不太会直接去和你沟通,而是让副总裁去传达,副总裁呢可能会让部门经理去传达,这种一层一层的关系是逐步解耦的,每个人只跟自己的朋友联系。
好了回到我们的外观模式,优点大家肯定能看到,简化复杂步骤,与朋友保持联系。但是他也有缺陷,外观类违反开闭原则了,当我们把子系统修改了,那外观类跟着也得修改。不过对于客户端来说他是保持不变的,至于违反了某原则咱们还是得要看场景,有些情况下轻度违反反而降低了系统的复杂度。设计外观模式一定要想好,切忌不要过度封装,将原本不需要隐藏的步骤也封装到外观类的某个接口中,使外部无法去调用了。
GOF定义:为子系统中的一组接口提供一个统一的外观,使得子系统更加容易使用