定义
外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。
使用场景
- 当你要为一个复杂子系统提供一个简单接口时。
- 客户程序与抽象类的实现部分之间存在着很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
- 当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点,如果子系统之间是相互依赖的,你可以让他们仅通过Facade进行通讯,从而简化了他们之间的依赖关系。
结构
模式所涉及的角色有:
Client : 客户端程序。
Facade : 对外的统一入口,即外观对象。
SubSystem : 子系统或者子服务等等。
实现
编程嘛,抽象于生活高于生活,接下来我们用生活中智能家居的小例子来分析一下外观模式。智能家居为什么会流行,其中一个原因肯定是方便,我们用一个中央处理器就可以管理我们所有的智能家居产品,类似的还有现在的一站式服务。那么用户就是Client角色,中央处理器就是Facade角色,音箱、TV、空调等等就是SubSystem角色。
Facade角色
public class Facade {
private Light mLight = new Light();
private AirCondition mAirCondition = new AirCondition();
/**
* 还可能会有方法集,比如我的习惯是下班回家,开灯、开空调,空调温度调节到20度
*/
public void doMyHabit(){
mLight.lightOn();
mAirCondition.airConditionaOn();
mAirCondition.setTemperature(20);
}
public void lightOn(){
mLight.lightOn();
}
public void lightOff(){
mLight.lightOff();
}
public void airConditionaOn() {
mAirCondition.airConditionaOn();
}
public void airConditionaOff() {
mAirCondition.airConditionaOff();
}
public void setTemperature(int temperature) {
mAirCondition.setTemperature(temperature);
}
}
子系统
public class Light {
public void lightOn(){
Log.e("Light","on");
}
public void lightOff(){
Log.e("Light","off");
}
}
public class AirCondition {
public void airConditionaOn() {
Log.e("AirCondition", "on");
}
public void airConditionaOff() {
Log.e("AirCondition", "off");
}
public void setTemperature(int temperature) {
Log.e("AirCondition", "temperature:" + temperature);
}
}
不知道大家有没有发现一个问题,外观模式和我们上篇说的适配器模式是不是有一些相似呢?
Facade与Adapter和Proxy有类似之处,但是Proxy注重在为Client-Subject提供一个访问的中间层,Adapter注重对接口的转换与调整,而Facade所面对的往往是多个类或其他程序单元,通过重新组合各类及程序单元,对外提供统一的接口/界面。
在Android中,Context类族是比较重要的,关于这些,在从装饰者模式到Context类族,Android Handler 消息机制(解惑篇)中已经做过说明,这里就不再画UML图了。
它是提供应用环境(application environment)信息的接口。通过它可以访问到应用的资源和类,以及进行一些系统级别的操作,比如加载activity、发送广播和接收intent等。这代表什么呢,Context类给我们提供了一站式服务,这里当然应用了外观模式。
在应用启动时,首先会fork一个子进程,并且调用ActivityThread.main方法启动该进程。ActivityThread又会构建Application对象,然后和Activity、ContextImpl关联起来,然后再调用Activity的onCreate、onStart、onResume函数使Activity运行起来。
Activity启动之后,Android给我们提供了操作系统服务的统一入口,也就是Activity本身。这些工作并不是Activity自己实现的,而是将操作委托给Activity父类ContextThemeWrapper的mBase对象,这个对象的实现类就是ContextImpl ( 也就是performLaunchActivity方法中构建的ContextImpl )。
ContextImpl内部封装了一些系统级别的操作,有的子系统功能虽然没有实现,但是也提供了访问该子系统的接口,比如获取ActivityManager的getActivityManager方法。
外观模式非常的简单,只是封装了子系统的操作,并且暴露接口让用户使用,避免了用户需要与多个子系统进行交互,降低了系统的耦合度、复杂度。
测试代码已上传到github。