1. 具体需求
组建一个家庭影院:
DVD播放器、投影仪、自动屏幕、环绕立体声、爆米花机,要求完成使用家庭影院的功能,其过程为:
直接用遥控统筹各设备开关:
- 开爆米花机
- 降下屏幕
- 开投影仪
- 开音响
- 开DVD,选DVD
- 拿爆米花
- 调暗灯光
- 播放
- 观影结束后,关掉各种设备
2. 传统解决方式
2.1 类图
2.2 问题分析
- 在ClientTest类的main方法中,创建各个子系统的对象,并直接去调用子系统(对象)相关方法,会造成调用过程混乱,没有清晰的过程。
- 不利于在ClientTest类中去维护对子系统的操作
2.3 解决思路
定义一个高层接口,给子系统中的一组接口提供一个一致的界面(比如在高层接口提供四个方法ready、play、pause、end),用来访问子系统中的一群接口。
也就是说:通过定义一个一致的接口(界面类),用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关系这个子系统的内部细节——>外观模式。
3. 外观模式
3.1 基本介绍
1)外观模式(Facade),也叫“过程模式”,外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
2)外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节
3.2 原理类图
3.3 角色分析
1)外观类(Facade):聚合子系统,为调用端提供统一的调用接口,外观类知道哪些子系统负责处理请求,从而将调用端的请求代理给适当子系统对象。
2)调用者(Client):外观接口的调用者。
3)子系统的集合:指模块或者子系统,处理Facade,对象指派的任务,它是功能的实际提供者。
4. 外观模式解决方式
4.1 传统方式解决方式说明
1)外观模式可以理解为转换一群接口,客户只要调用一个接口,而不用调用多个接口才能达到目的。比如:在pc上安装软件的时候经常有一键安装选项(省去选择安装目录、安装的组件等等),还有就是手机的重启功能(把关机和启动合为一个操作)。
2)外观模式就是解决多个复杂接口带来的使用困难,起到简化用户操作的作用
3)示意图
4.2 外观模式实例
1)使用外观模式完成家庭影院项目
2)思路分析和图解(类图)
3)代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| public class DVDPlayer { private static DVDPlayer instance = new DVDPlayer();
public static DVDPlayer getInstance(){ return instance; }
public void on(){ System.out.println("DVD on……"); }
public void off(){ System.out.println("DVD off……"); }
public void pause(){ System.out.println("DVD pause……"); }
public void play(){ System.out.println("DVD play……"); } }
public class Popcorn { private static Popcorn instance = new Popcorn();
public static Popcorn getInstance(){ return instance; }
public void on(){ System.out.println("Popcorn on……"); }
public void off(){ System.out.println("Popcorn off……"); }
public void pop(){ System.out.println("Popcorn pop……"); } }
public class Projector { private static Projector instance = new Projector();
public static Projector getInstance(){ return instance; }
public void on(){ System.out.println("Projector on……"); }
public void off(){ System.out.println("Projector off……"); }
public void focus(){ System.out.println("Projector focus……"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| public class HomeTheaterFacade { private TheaterLight light; private Popcorn popcorn; private Stereo stereo; private Projector projector; private Screen screen; private DVDPlayer dvdPlayer;
public HomeTheaterFacade() { super(); light = TheaterLight.getInstance(); popcorn = Popcorn.getInstance(); stereo = Stereo.getInstance(); projector = Projector.getInstance(); screen = Screen.getInstance(); dvdPlayer = DVDPlayer.getInstance(); }
public void ready() { popcorn.on(); popcorn.pop(); screen.down(); projector.on(); stereo.on(); dvdPlayer.on(); light.dim(); }
public void play() { dvdPlayer.play(); }
public void pause() { dvdPlayer.pause(); }
public void end() { popcorn.off(); light.bright(); screen.up(); projector.off(); stereo.off(); dvdPlayer.off(); } }
|
1 2 3 4 5 6 7 8 9 10 11
| public class Client { public static void main(String[] args) { HomeTheaterFacade facade = new HomeTheaterFacade(); facade.ready(); facade.play(); facade.end(); } }
|
5. 外观模式在MyBatis框架应用的源码分析
1)MyBatis中的Configuration去创建MetaObject对象使用到了外观模式
2)代码分析+Debug源码+示意图
3)对源码中使用到的外观模式的角色类图
6. 外观模式的注意事项和细节
1) 外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性 2) 外观模式对客户端与子系统的轉合关系 - 解轉,让子系统内部的模块更易维护和扩展 3) 通过合理的使用外观模式,可以帮我们更好的划分访问的层次 4) 当系统需要进行分层设计时,可以考虑使用 Facade 模式 5) 在维护一个遗留的大型系统时,可能这个系统己经变得非常难以维护和扩展,此时可以考虑为新系统开发一个Facade 类,来提供遗留系统的比较清晰简单的接口,让新系统与 Facade 类交互,提高复用性 6)不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好。要以让系统有层次,利于维护为目的。