一、概述
我们在使用三方SDK库时,SDK都会提供一个统一的入口,经过封装后我们就可以用很少的方法,就能达到所需的目的,简化了我们的操作。比如使用手机时,我们只需要点击屏幕就可以使用相应的APP,而所有的软件和硬件都封装在了手机外壳里面;再比如我们去饭店点菜吃饭,服务员就扮演的是这个店的外观模式,给我们点菜、倒水时只需要通过这个服务员,所有的炒菜、烧水都是在后厨完成,我们无需关心。
外观模式包含两个角色:
- Facade(外观角色):外观模式的核心角色。在客户端可以调用他的方法,在外观角色中可以知道相关的子系统的功能和责任;在正常情况下,他将所有从客户端的请求委派到各个相应的子系统,传递给相应的子系统对象处理
- SubSystem(子系统角色):在软件系统中可以有一个或多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用。对于子系统而言,外观类只是另一个客户端。
还是老样子,就以在饭店吃饭为例,用代码来说明。
二、使用
首先我们要创建几个子系统,这里为了方便理解,每个子系统就以一个单独的类来做说明。我们去饭店吃饭,一般都会有先点菜,再倒茶,(中间省略吃饭的过程),最后买单这样一个流程系统。我们点完菜后,后厨开始洗菜、摘菜、炒菜、上菜等步骤;让服务员给我们到点茶水,后厨开始烧水、放茶叶、倒水等步骤;买单就有清算、付钱等操作。所以这里就分别建立3个类来封装这些操作:步骤一代表点菜、步骤二代表倒茶、步骤三代表买单。
/**
* 步骤一:后厨洗菜、摘菜、炒菜、上菜
*/
public class StepOne {
private static final String TAG = "XXX";
//摘菜
public void pick(){
Log.e(TAG, "后厨开始摘菜");
}
//洗菜
public void wash(){
Log.e(TAG, "后厨开始洗菜");
}
//炒菜
public void stirFry(){
Log.e(TAG, "后厨开始炒菜");
}
//上菜
public void serve(){
Log.e(TAG, "炒完,上菜");
}
}
/**
* 步骤二:服务员烧水、放茶叶、倒茶
*/
public class StepTwo {
private static final String TAG = "XXX";
//烧水
public void boiling(){
Log.e(TAG, "服务员烧水");
}
//放茶叶
public void putTea(){
Log.e(TAG, "服务员放茶叶");
}
//倒水
public void pourWater(){
Log.e(TAG, "开始倒水");
}
}
/**
* 步骤三:清算、付钱
*/
public class StepThree {
private static final String TAG = "XXX";
//清算
public void settleAccounts(){
Log.e(TAG, "清算账单");
}
//付钱
public void pay(){
Log.e(TAG, "付钱");
}
}
然后就是外观类,可以看到在各个方法中都分别调用了各个步骤的相关方法。当然不一定每个方法负责的是一个模块,也可以相互穿插调用。
/**
* 外观类
*/
public class Facade {
private static final StepOne stepOne = new StepOne();
private static final StepTwo stepTwo = new StepTwo();
private static final StepThree stepThree = new StepThree();
//点单
public void order(){
stepOne.pick();
stepOne.wash();
stepOne.stirFry();
stepOne.serve();
}
//加水
public void water(){
stepTwo.boiling();
stepTwo.putTea();
stepTwo.pourWater();
}
//结账
public void pay(){
stepThree.settleAccounts();
stepThree.pay();
}
}
最后进行测试一下,打印输出如下图所示。
Facade facade = new Facade();
facade.order();
facade.water();
facade.pay();

三、总结
外观模式使用起来是非常简单的,只是对内部的调用进行了一次封装,减少了系统的耦合度,使客户端所需要调用的类的数目减少,使得就简化了客户端的代码;并且子系统如果发生修改不会影响客户端代码,只要修改外观模式就可以;一个子系统的修改对其它子系统没有任何影响,而且子系统内部变化也不会影响到外观模式。
外观模式也有一些缺点,比如客户端虽然减少了对子系统调用过程,但不是完全限制客户端对子系统的调用,如果子系统有所改变那么相应的客户端也要跟着改变;增加新的子系统就可能修改外观类的源代码,不符合开闭原则。
github地址:github.com/leewell5717…