外观模式又称为门面模式,它提供了一个统一的接口去访问多个子系统的多个不同的接口,为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。外观模式的本质就是化零为整,通过引入一个中介类,把各个分散的功能组合成一个整体,只对外暴露一个统一的接口。
上一篇文章中介绍了享元模式,它使用共享对象并有效地支持大量的细粒度的对象,而外观模式把过度拆分的分散功能,组合成一个整体,从而对外提供一个统一的接口。就像明朝时期的内阁制度。明初朱元璋废丞相,六部直接与皇帝打交道。后来,朱棣多次远征漠北,精力有限,于是设立内阁,将旨意直接下达内阁,由内阁去分管六部。如下图:
外观模式的角色划分:
外观角色(Facade):为多个子系统对外提供一个共同的接口。子系统角色(SubSystem):实现系统的部分功能,客户端通过外观角色访问它。客户角色(Client):通过一个外观角色访问各个子系统的功能。 外观模式的类图如下:
(1)优点
减少系统的相互依赖,所有的以来都是对Facade对象的依赖,与子系统无关。提高灵活性。不管子系统内部如何变化,只要不影响Facade对象,任何活动都是自由的。提高安全性。Facade中未提供的方法,外界就无法访问。(2)缺点
不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性。如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则。场景描述:小李正在下班的路上,他的老板打电话过来说他要去北京出差20天,让小李帮忙预定酒店、机票等等一系列事务。这里,我们分析一下这个实现过程:
假设现在有四个子系统类:机场类——Airport、酒店类——Restaurant、宾馆类——Hotel、司机类——Driver。对于Boss来说,他不需要知道子系统内的每个类,只需要告诉小李,让小李去安排。而小李作为秘书,充当的是外观角色类,对子系统中的四个类进行引用即可。类图如下:
代码实现如下:
机场类代码:
/** * 机场类 */ public class Airport { /** * 订票 * @param src 出发地 * @param dest 目的地 */ public void ticket(String src, String dest){ System.out.println("订购了从 " + src + " 到 " + dest + "票"); } }宾馆类代码:
/** * 宾馆类 */ public class Hotel { /** * 预定房间 * @param days 天数 */ public void reserve(int days){ System.out.println("预定了" + days + "天的房间"); } }酒店类:
/** * 酒店类 */ public class Restaurant { /** * 订酒席 * @param num 人数 */ public void deskOrder(int num){ System.out.println("订了一个 " + num + " 人的酒席订单"); } }司机类:
/** * 司机类 */ public class Driver { /** * 开车 * @param dest 目的地 */ public void drive(String dest){ System.out.println("司机开车到 " + dest); } }秘书类:
/** * 秘书类 */ public class Secretary { private Driver driver = new Driver(); private Hotel hotel = new Hotel(); private Restaurant restaurant = new Restaurant(); private Airport airport = new Airport(); /** * 出差 * @param dest 目的地 * @param days 出差天数 */ public void businessTrip(String dest, int days){ airport.ticket("西安", dest); driver.drive("西咸机场"); hotel.reserve(days); } /** * 预定酒席 * @param num 人数 */ public void dine(int num){ restaurant.deskOrder(num); driver.drive("酒店"); } }老板类:
public class Boss { public static void main(String[] args) { Secretary secretary = new Secretary(); System.out.println("老板告诉秘书去北京出差20天"); secretary.businessTrip("北京", 20); System.out.println("================="); System.out.println("老板说要请12个人吃饭"); secretary.dine(12); } }执行结果如下: