根据单一权责原则,软件中将一个系统划分为若干个子系统有利于降低整个系统的复杂性,使客户类与子系统之间的通信和相互依赖关系达到最小,方法之一就是引入一个外观角色,为子系统的访问提供一个简单而单一的入口。外观模式通过引入一个新的外观角色来降低原有系统的复杂度,同时降低客户类与子系统类的耦合度。
(这里的子系统是广义的概念,可以是一个类,一个功能模块,系统的一个组成部分或者一个完整的系统)
如果没有外观角色,每个客户端可能需要和多个子系统之间进行复杂的交互,系统的耦合度很大,简化示意图如下:
而引入外观角色后,客户端只需直接与外观角色交互,客户端与子系统之间的原有复杂度由外观角色实现,从而降低系统耦合度,简化示意图如下:
外观模式要求一个子系统的外部与其内部的通信通过一个统一的外观角色进行,外观角色将客户端与子系统的内部复杂性分隔开,使得客户端只需要与外观角色打交道,而不需要与子系统内部的很多对象打交道。
外观模式:外部与一个子系统的通信通过一个统一的外观角色进行,为子系统中的一组接口提供一个一致的入口。
外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
外观模式又叫门面模式,是一种对象结构型模式。
通常实现如下:
class Facade
{
private SubSystemA subSystemA = new SubSystemA();
private SubSystemB subSystemB = new SubSystemB();
private SubSystemC subSystemC = new SubSystemC();
public void method()
{
subSystemA.method();
subSystemB.method();
subSystemC.method();
}
}
class SubSystemA
{
public void method()
{
System.out.println("子系统A");
}
}
class SubSystemB
{
public void method()
{
System.out.println("子系统B");
}
}
class SubSystemC
{
public void method()
{
System.out.println("子系统C");
}
}
使用外观模式的原因就是简化客户端的调用,在这里只需定义外观对象并调用业务方法即可:
Facade facade = new Facade();
facade.method();
设计一个文件加密系统,加密流程包括三部分:读取文件,加密文件,保存文件。这三个操作相对独立,并且封装在三个不同的类中,使用外观模式设计该系统。
设计如下:
FileReader
+Encrypt
+FileWriter
Facade
FileReader
:文件读取类Encrypt
:文件加密类FileWriter
:文件保存类代码如下:
public class Test
{
public static void main(String[] args) {
Facade facade = new Facade();
facade.fileEncrypt("111");
}
}
class FileReader
{
public void read(String name)
{
System.out.println("读取文件"+name);
}
}
class Encrypt
{
public void encrypt(String name)
{
System.out.println("加密文件"+name);
}
}
class FileWriter
{
public void write(String name)
{
System.out.println("保存文件"+name);
}
}
class Facade
{
private FileReader reader = new FileReader();
private Encrypt encrypt = new Encrypt();
private FileWriter writer = new FileWriter();
public void fileEncrypt(String name)
{
reader.read(name);
encrypt.encrypt(name);
writer.write(name);
}
}
这里的例子比较简单,其实就是将读取,加密以及保存操作用外观角色包装起来,方便客户端调用。
在标准的外观模式结构中,如果需要增加,删除或修改外观类交互的子系统类,必须修改外观类或客户端的源代码,这将违背开闭原则,比如上面的例子中需要更换一种加密方法,也就是换一个加密类,这样需要直接修改外观类。
可以通过引入抽象外观类来解决该问题,引入后,客户端可以针对抽象外观类进行编程,对于新的业务需求不需要修改原有的外
观类,只需要新增一个对应的具体外观类即可。
首先定义抽象外观类,接着具体外观类继承或者实线抽象外观类即可。客户端针对抽象外观类进行编程,在运行时再确定具体的外观类,比如在上面例子的基础上修改加密方法,首先定义抽象外观类(这里是接口,只有一个加密方法):
interface AbstractFacade
{
void encrypt(String name);
}
接着定义具体外观类:
class Facade1 implements AbstractFacade
{
private FileReader reader = new FileReader();
private Encrypt1 encrypt1 = new Encrypt1();
private FileWriter writer = new FileWriter();
@Override
public void encrypt(String name)
{
reader.read(name);
encrypt1.encrypt(name);
writer.write(name);
}
}
class Facade2 implements AbstractFacade
{
private FileReader reader = new FileReader();
private Encrypt2 encrypt2 = new Encrypt2();
private FileWriter writer = new FileWriter();
@Override
public void encrypt(String name)
{
reader.read(name);
encrypt2.encrypt(name);
writer.write(name);
}
}
这两个类除了加密方法不一样其他都一样,测试:
AbstractFacade facade = new Facade1();
facade.encrypt("111");
facade = new Facade2();
facade.encrypt("222");
引入抽象外观类后,客户端针对抽象外观类进行编程,运行时确定具体外观类,输出如下:
如果觉得文章好看,欢迎点赞。
同时欢迎关注微信公众号:氷泠之路。