一、举个栗子
小明每天回家都会先打开灯,空气净化器,电热水器烧上水,放上音乐,如果天气热的话,再打开空调。
写成代码
lights.on();//打开灯
airCleaner.on();//打开空气净化器
airCleaner.setMode(auto);//设置自动模式
waterHeater.on();//打开电热水器
waterHeater.setTemperature(40);//水温40度
player.on();//打开音响
play.play(music);//放上音乐
...
//涉及到太多类了!!!
出门的时候,还得反向操作把它们都关掉。
如果升级了系统,还得重新学习另一套操作流程。
那么就使用外观模式来改造成智能家居吧。
二、设计思路
1、创建一个名为HomeFacade新类,对外暴露几个简单的方法,如open()
2、这个新类把灯,音响,空调等视为子系统,让open()去调用他们
3、客户端去调用HomeFacade所提供的方法,而无须再分步骤调用子系统,就可以完成所有操作
image.png
外观只提供更直接的操作,并没有将原来的子系统隔离起来,还是可以调用原来的子系统的。
具体实现:
public class HomeFacade {
//所用到的子系统组件
musicPlayer player;
Light light;
...
//将子系统的每个组件传入构造器,并赋值给实例变量
public HomeFacade(musicPlayer player, Light light, ...) {
this.player = player;
this.light = light;
...
}
public void open() {
lights.on();//打开灯
airCleaner.on();//打开空气净化器
airCleaner.setMode(auto);//设置自动模式
waterHeater.on();//打开电热水器
waterHeater.setTemperature(40);//水温40度
player.on();//打开音响
play.play(music);//放上音乐
}
public void endMovie() {
lights.off();
airCleaner.off();
waterHeater.();
...
}
}
//进家门
public class HomeTestDrive {
public static void main(String[] args) {
HomeFacade home = new HomeFacade(player, light, ...);
//使用简化的接口,打开各种电器,然后关闭各种电器
home.open();
home.close();
}
}
三、外观模式
1、定义:
外观模式提供了一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层接口,让子系统更容易使用。
外观模式封装了子系统的操作,暴露一个统一的接口让用户使用,避免了用户需要与多个子系统进行交互,降低了系统的耦合度、复杂度。如果没有外观模式的封装,那么用户就必须知道各个子系统的相关细节,子系统之间的交互必然造成纠缠不清的关系,影响系统的稳定性、复杂度。
2、类图
image.png
Tips:
最少知识原则:要减少对象间的交互,只和密友交谈。也就是说,不要让太多的类耦合在一起,避免修改系统中的一部分,会影响其他部分,如果许多类之间相互依赖,那这个系统的维护成本就会很高,也不容易被他人了解。
3、与装饰者模式,适配器模式的区别
装饰者模式是将一个对象包装起来,增加新的行为和责任
image.png
适配器模式是现有类的接口不符合需要,必须转换成不同的接口,(将一个对象包装起来改变接口)以符合客户的期望
外观模式可以简化并统一一个很大很复杂的接口,(将对象“包装”起来简化接口)将用户从组件的子系统中解耦
image.png
四、外观模式在Android中的应用
在Android中,Context是最重要的一个类型。它封装了很多重要的操作,比如startActivity()、sendBroadcast()等,这些功能内部的实现非常复杂,但是我们无需关心它内部实现了什么,我们只关心它帮我们启动Activity,帮我们发送了一条广播,绑定了Activity等等就够了。
Context是一个抽象类,它只是定义了抽象接口,真正的实现在ContextImpl类中,在ContextImpl内部有很多xxxManager类的对象,也就是前面所说的各种子系统。
image.png