今天我们继续来学习前面没有学完的结构型设计模式中的一种:门面模式。门面模式也是一种不太常用的设计模式。所以,我们今天依旧是了解为主,暂时不去深入的学习。

概述

门面模式:(Facade Design Pattern)门面模式也叫外观模式,门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。

门面模式原理和实现也比较简单,应用场景也比较明确,主要在接口设计方面使用。

何时使用:

  • 解决易用性问题。
  • 解决性能问题。
  • 解决分布式事务问题。

UML 类图:

设计模式——门面模式_客户端


角色组成:

  1. 门面角色:客户端调用这个角色的方法。此角色知晓相关的子系统的功能和责任。正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统中去。
  2. 子系统角色:可以同时有一个或者多个子系统。每个子系统都不是一个单独的类,而是一个类的集合。每一个子系统都可以被客户端直接调用,或者被门面角色直接调用。子系统并不知道门面的存在,罪域子系统而言,门面仅仅是另一个客户端而已。

代码实现

子系统角色中的类:ModuleA.java、ModuleB.java、ModuleC.java

public class ModuleA {
//示例方法
public void testA(){
System.out.println("调用ModuleA中的testA方法");
}
}


public class ModuleB {
//示例方法
public void testB(){
System.out.println("调用ModuleB中的testB方法");
}
}


public class ModuleC {
//示例方法
public void testC(){
System.out.println("调用ModuleC中的testC方法");
}
}

门面角色类:Facade.java

public class Facade {
//示例方法,满足客户端需要的功能
public void test(){
ModuleA a = new ModuleA();
a.testA();
ModuleB b = new ModuleB();
b.testB();
ModuleC c = new ModuleC();
c.testC();
}
}

客户端角色类:Client.java

public class Client {

public static void main(String[] args) {

Facade facade = new Facade();
facade.test();
}

}

Facade类其实相当于A、B、C模块的外观界面,有了这个Facade类,那么客户端就不需要亲自调用子系统中的A、B、C模块了,也不需要知道系统内部的实现细节,甚至都不需要知道A、B、C模块的存在,客户端只需要跟Facade类交互就好了,从而更好地实现了客户端和子系统中A、B、C模块的解耦,让客户端更容易地使用系统。

解决的问题

1. 解决易用性问题

这个很容易理解,门面模式可以用来封装系统的底层实现,隐藏系统的复杂性,提供一组更加简单易用、更高层的接口。比如,Linux 系统调用函数就可以看作一种“门面”。它是 Linux 操作系统暴露给开发者的一组“特殊”的编程接口,它封装了底层更基础的 Linux 内核调用。

2. 解决性能问题

我们知道,App 和服务器之间是通过移动网络通信的,网络通信耗时比较多,为了提高 App 的响应速度,我们要尽量减少 App 与服务器之间的网络通信次数。

假设,完成某个业务功能(比如显示某个页面信息)需要“依次”调用 a、b、d 三个接口。如果我们发现过多的网络通信次数造成客户端响应速度慢,此时就可以利用门面模式,让后端服务器提供一个包裹 a、b、d 三个接口调用的接口 x。App 客户端调用一次接口 x 就可以了,减少了网络通信次数。

3. 解决分布式事务问题
假设在一个金融系统中,用户注册需要创建用户和创建用户钱包。用户注册需要支持事务,也就是创建用户和钱包两个操作,要么都成功,要么都失败,不能一个成功,一个失败。
要想两个接口调用在一个事务中执行,是比较难以实现的。此时,我们就可以使用门面模式,将两个接口操作实现放在一个接口中,并使用 Spring 框架提供的事务来控制。

总结

与代理模式的区别

在学习门面模式时,会发现它不仅与代理模式很像,与装饰器模式也很类似;

相似点:

  • 都引入了中介类(对象)
  • 中介对象都引用并把功能委托给了原对象
  • 都起到了”代理”功能

区别

  • 代理侧重于对原对象的访问控制(当然也可以不是控制而是功能增强)
  • 代理与原类实现相同的抽象(相同接口或直接继承原业)
  • 代理只代理一个类
  • 门面侧重于功能整合(多个小系统或小对象整合成一个功能丰富的大对象)
  • 门面可以与子系统具有不同的抽象(具有不同的接口,可以对方法重新起名)
  • 门面代理的是一系列类