外观模式(Facade)在开发过程中的运用频率非常高,尤其是在现阶段各种第三方SDK充斥在我们的周边,而这些SDK很大概率会使用外观模式。通过一个外观类使得整个系统的接口只有一个统一的高层接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节。当然,在我们的开发过程中,外观模式也是我们封装API的常用手段,例如网络模块、ImageLoader模块等。
外观模式又叫门面模式。外观模式为子系统中一组不同的接口提供统一的接口。外观模式定义了上层接口,通过降低复杂度和隐藏子系统间的通信及依存关系,让子系统更易于使用。
3.1 为一个复杂子系统提供一个简单接口。子系统往往因为不断演化而变得越来越复杂,甚至可能被替换。大多数模式使用时都会产生更多、更小的类,在这使子系统更具可重用性的同时也更容易对子系统进行定制、修改,这种易变性使得隐藏子系统的具体实现变得尤为重要。Facade可以提供一个简单统一的接口,对外隐藏子系统的具体实现、隔离变化。
3.2 当你需要构建一个层次结构的子系统时,使用Facade模式定义了子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过Facade接口进行通信,从而简化了它们之间的依赖关系。
外观角色(Facade):是模式的核心,他被客户client角色调用,知道各个子系统的功能。同时根据客户角色已有的需求预订了几种功能组合
子系统角色(Subsystem classes):实现子系统的功能,并处理由Facade对象指派的任务。对子系统而言,facade和client角色是未知的,没有Facade的任何相关信息;即没有指向Facade的实例。
业务场景如下:
有一位乘客需要乘坐出租车,出租车司机为驾驶出租车的一组复杂接口提供了一个简化了的接口。如图:
通过此图可以看出整个出租车服务作为一个封闭系统,包括一名出租车司机(外观角色)、一辆车(子系统角色)、一个计价器(子系统角色)。同系统交互的唯一途径是通过CabDriver中定义的接口driveToLocation:x。一旦乘客(客户client角色)向出租车司机发出driveToLocation:x消息。CabDriver就会收到消息。司机需要操作两个子系统---Taximeter(计价器)和Car。CabDriver先启动(start)Taximeter,让他开始计价,然后司机对汽车会松刹车(releaseBrakes)、换挡(changeGears)、踩油门(pressAccelerator),把车开走。直到到达了地点x,CabDriver会松油门(releaseAccelerator)、踩刹车(pressBrakes)、停止(stop)Taximeter,结束行程。
一切都发生于发给CabDriver的一个简单的driveToLocation:x命令之中。无论两个子系统有多么复杂,它们隐藏于乘客的实现之外。因为CabDriver是在为出租车子系统中的其他复杂接口提供了一个简化的接口。CabDriver像“外观”一样,处于乘客与出租车子系统之间。
参考代码地址:https://github.com/zhiyoukaifa/Pattern
外观模式是一个高频率使用的设计模式,它的精髓就在于封装二字。通过一个高层次结构为用户提供统一的API入口,使得用户通过一个类型就基本能够操作整个系统,这样减少了用户的使用成本,也能够提升系统的灵活性。
1.对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易。通过引入外观模式,客户代码将变得很简单,与之关联的对象也很少。
2.实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。
3.降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
4.只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。
1.外观类接口膨胀。由于子系统的接口都有外观类统一对外暴露,使得外观类的API接口较多,在一定程度上增加了用户使用成本。
2.不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。
3.在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
参考书籍:
《Objective-C编程之道 iOS设计模式解析》
《Android源码设计模式解析与实战》
参考链接:
https://www.cnblogs.com/wuchanming/p/4483140.html