一 . 模式动机
- 在系统比较复杂时,用户与系统之间的关系也会变得复杂,这时候我们可以适用一个外观角色,作为用户和子系统之间的一个角色,用户只需要与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现。
二 . 模式定义
- 外观模式(Facade外观模式 Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这个子系统更加容易适用。外观模式又称门面模式,是一种对象行结构模式。
- 简单来说就是在外观类中引用子系统的类,客户通过外观类去调用子系统的类,无需直接与子系统打交道。
三 . 模式结构
(图片来源于网络)
- Facade外观模式:外观类
- SubSystem:子系统类
三 . 模式分析
- 外观模式很常用,而且结构简单易懂
- 根据“单一职责原则”,在软件中将一个系统划分为若干个子系统有利于降低整个系统的复杂性,引入外观对象,为子系统提供一个简单而单一的接口。
- 外观模式也是“迪米特法则”的体现,通过引入一个新的外观类可以降低原有系统的复杂度,同时降低客户类与子系统类的耦合度。
四 . 模式实例
-
假设现在要开一家公司,开公司要和税务局,工商局,质检局,银行打交道。如果我们都亲历亲为,非常麻烦,因此我们可以找一个熟悉这个流程的人替我们去办理这些业务。
-
UML图
(图片来源于网络) -
子系统类
public interface ZJJ {
void zjj();
}
class ConcreteZJJ implements ZJJ{
@Override
public void zjj() {
System.out.println("质检");
}
}
public interface SWJ {
//报税
void BS();
}
class ConcreteSWJ implements SWJ {
@Override
public void BS() {
System.out.println("报税");
}
}
public interface GSJ {
void gsj();
}
class ConcreteGSJ implements GSJ {
@Override
public void gsj() {
System.out.println("办理商业名");
}
}
public interface Bank {
void bank();
}
class ConcreteBank implements Bank {
@Override
public void bank() {
System.out.println("办理企业账户");
}
}
- 外观类
public class Facade外观模式 {
private GSJ gsj;
private ZJJ zjj;
private SWJ swj;
private Bank bank;
public void regist(){
gsj = new ConcreteGSJ();
zjj = new ConcreteZJJ();
swj = new ConcreteSWJ();
bank = new ConcreteBank();
gsj.gsj();
swj.BS();
bank.bank();
zjj.zjj();
}
}
- 测试类
public class Client {
public static void main(String[] args) {
Facade外观模式 regist = new Facade外观模式();
regist.regist();
}
}
- 测试结果
E:\Java\jdk1.8.0_171\bin\java.exe "-javaagent:E:\idea\IntelliJ IDEA 2019.1.3\lib\idea_rt.jar=51335:E:\idea\IntelliJ IDEA 2019.1.3\bin" -Dfile.encoding=UTF-8 -classpath "E:\Java\jdk1.8.0_171\jre\lib\charsets.jar;E:\Java\jdk1.8.0_171\jre\lib\deploy.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;E:\Java\jdk1.8.0_171\jre\lib\javaws.jar;E:\Java\jdk1.8.0_171\jre\lib\jce.jar;E:\Java\jdk1.8.0_171\jre\lib\jfr.jar;E:\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;E:\Java\jdk1.8.0_171\jre\lib\jsse.jar;E:\Java\jdk1.8.0_171\jre\lib\management-agent.jar;E:\Java\jdk1.8.0_171\jre\lib\plugin.jar;E:\Java\jdk1.8.0_171\jre\lib\resources.jar;E:\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Design pattern\out\production\Design pattern" Facade外观模式.Client
办理商业名
报税
办理企业账户
质检
Process finished with exit code 0
- 可以看到客户不需要一个一个和那些部门打交道,只需要和外观类打交道就可以满足需求。
五 . 模式优缺点
- 优点:
- 对客户屏蔽子系统组件,减少客户处理的对象数目并且使得子系统使用起来更加容易。
- 实现类子系统与客户之间的松耦合关系
- 降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程。
- 只是提供一个访问子系统的统一接口,并不影响用户直接受用子系统类。
- 缺点:
- 不能很好的限制用户,如果对客户访问子系统做了太多限制则减少了可变性和灵活性。
- 在不引入抽象外观类的情况下增加新的子系统要修改外观类的源代码,违背了“开闭原则”。
六 . 适用场景
- 要为一个复杂的子系统提供一个简单接口时。
- 客户程序与多个子系统之间存在很大的依赖性。
- 在层次化结构中,可以使用外观模式定义系统中每一次的入口,层与层之间不需要直接联系,而通过外观类建立联系,降低层之间的耦合度。
七 . 模式应用
- JDBC数据库操作
八 . 模式扩展
- 一个系统有多个外观类,很多情况下为了节约系统资源,一般将外观类设计为单例类。这并不以为着在整个系统中只能有一个外观类,一个系统可以有多个外观类,每个外观类负责和一些特定的子系统交互,向用户提供相应的业务功能。
- 不要试图通过外观类为子系统增加新行为。
- 抽象外观类的引入,刚在缺点中说到外观类违背了“开闭原则”,可以通过引入抽象外观类在一定程度上解决该问题。