自助游(图1)算法
旅行社(图2)编程
不知道你们有没有经过旅行社报团出去旅游的经历?这是一个很好的外观模式的应用。设计模式
方式一:客户直接调用各个子系统的功能,和各个子系统之间造成紧耦合的关系(上图一)
方式二:提供一个高层接口,该高层接口负责和子系统进行交互,并向客户提供须要使用的接口(上图二)
从上面两种方式的图式结构能够看到,对客户来讲,方式二比方式一要好用不少,由于在方式二中,客户不须要知道各个子系统的逻辑,只须要和高层接口交互就能够了。实际上方式二,就是咱们这里要说的外观模式了。架构
若是这里不该用外观模式,咱们(上图中的Client),就得本身去联系交通工具、预约旅馆、饭馆、景点门票等,相信这样的旅程,你们会感受很累。有了外观角色(上图中的Facade),它会帮咱们去处理这些事情。工具
得墨忒耳定律(Law of Demeter,缩写LoD)亦稱為“最少知识原则(Principle of Least Knowledge)”,是一种软件开发的设计指導原則,特别是面向对象的程序设计。得墨忒耳定律是松耦合的一种具体案例。該原則是美国東北大學在1987年底在发明的。
这个原理的名称来源于希腊神话中的农业女神,孤独的得墨忒耳(Demeter)。spa
定义:一个对象应该对其余对象保持最少的了解。
问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另外一个类的影响也越大。架构设计
解决方案:尽可能下降类与类之间的耦合。设计
自从咱们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。不管是面向过程编程仍是面向对象编程,只有使各个模块之间的耦合尽可能的低,才能提升代码的复用率。低耦合的优势不言而喻,可是怎么样编程才能作到低耦合呢?那正是迪米特法则要去完成的。
迪米特法则又叫最少知道原则,最先是在1987年由美国Northeastern University的Ian Holland提出。通俗的来说,就是一个类对本身依赖的类知道的越少越好。也就是说,对于被依赖的类来讲,不管逻辑多么复杂,都尽可能地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。迪米特法则还有一个更简单的定义:只与直接的朋友通讯。首先来解释一下什么是直接的朋友:每一个对象都会与其余对象有耦合关系,只要两个对象之间有耦合关系,咱们就说这两个对象之间是朋友关系。耦合的方式不少,依赖、关联、组合、聚合等。其中,咱们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出如今局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要做为局部变量的形式出如今类的内部。code
最多见的比喻是:不要和陌生人说话对象
看看这个:假设我在便利店购物。付款时,我是应该将钱包交给收银员,让她打开并取出钱?仍是我直接将钱递给她?
再作一个比喻:人能够命令一条狗行走(walk),可是不该该直接指挥狗的腿行走,应该由狗去指挥控制它的腿如何行走。
迪米特法则能够简单说成:talk only to your immediate friends。 对于OOD来讲,又被解释为下面几种方式:一个软件实体应当尽量少的与其余实体发生相互做用。每个软件单位对其余的单位都只有最少的知识,并且局限于那些与本单位密切相关的软件单位。
迪米特法则的初衷在于下降类之间的耦合。因为每一个类尽可能减小对其余类的依赖,所以,很容易使得系统的功能模块功能独立,相互之间不存在(或不多有)依赖关系。
迪米特法则不但愿类之间创建直接的联系。若是真的有须要创建联系,也但愿能经过它的友元类来转达。所以,应用迪米特法则有可能形成的一个后果就是:系统中存在大量的中介类,这些类之因此存在彻底是为了传递类之间的相互调用关系——这在必定程度上增长了系统的复杂度。
设计模式中的门面模式(Facade)和中介模式(Mediator),都是迪米特法则应用的例子。
值得一提的是,虽然Ian Holland对计算机科学的贡献也仅限于这一条法则,其余方面的建树很少,可是,这一法则却不只仅局限于计算机领域,在其余领域也一样适用。好比,美国人就在航天系统的设计中采用这一法则。
外观模式为子系统中一组不一样的接口提供统一的接口。外观定义了上层接口,经过下降复杂度和隐藏子系统间的通讯及依存关系,让子系统易于使用。
API 的使用者彻底不知道这内部的业务逻辑有多么复杂。当咱们有大量的类而且它们使用起来很复杂并且也很难理解的时候,外观模式是一个十分理想的选择。
外观模式把使用和背后的实现逻辑成功解耦,同时也下降了外部代码对内部工做的依赖程度。若是底层的类发生了改变,外观的接口并不须要作修改。
这个定义,经过上面引言的图示讲解,应该很好理解了,这里再分析一下定义中的两个重要角色:
外观角色:就是引言图示中的“高层接口”,客户端能够调用这个角色的方法;另外,该角色知道相关的子系统的功能和责任。
子系统角色:能够同时有一个或者多个子系统。每个子系统均可以被客户端直接调用,或者被外观角色调用。
比方说今天我不想开车,因而打电话叫了出租车。只要出租车能把我送到目的地,我不在意车牌和型号。我会直接对司机说“我要去somePlace”,而后司机会执行一系列的命令
(松手刹、换挡、踩油门等等)。出租车司机抽象出了驾驶汽车的底层负责操做的细节。他经过提供驾驶服务(简化了接口),把我与本来复杂的车辆操做接口分离。出租车和我直接的接口只是一个简单的“我要去xxx”命名。
不少旧的面向对象应用程序中,可能有许多类分散于带有各类功能的系统中。要把这些类用于某个功能,须要知道所有细节才能在一组算法中使用它们。若是从逻辑上将其中一些类组合成一个简单的接口,可让这些类更易于使用。
Car定义了几个操其内部对象的方法,如pressBrakes、releaseBrakes、changGears...。客户端想要使用Car的内部功能,必须了解如何使用这些方法进行正确操做。
@interface Car : NSObject /// 踩刹车 - (void)pressBrakes; /// 松刹车 - (void)releaseBrakes; /// 换挡 - (void)changGears; /// 踩油门 - (void)pressAccelerator; /// 松油门 - (void)releaseAccelerator; @end @implementation Car - (void)pressBrakes { NSLog(@"car: 踩刹车"); } - (void)releaseBrakes { NSLog(@"car: 松刹车"); } - (void)changGears { NSLog(@"car: 换挡"); } - (void)pressAccelerator { NSLog(@"car: 踩油门"); } - (void)releaseAccelerator { NSLog(@"car: 松油门"); } @end
Taximeter自己是一个复杂的系统,它有两个让客户端操做其对象的方法。start和stop方法只是让Taximeter开始或中止。这里不深刻Taximeter的细节。
@interface Taximeter : NSObject /// 开始打表 - (void)start; /// 结束打表 - (void)stop; @end @implementation Taximeter - (void)start { NSLog(@"Taximeter: 开始打表"); } - (void)stop { NSLog(@"Taximeter: 结束打表"); } @end
目前,出租车服务系统里面有两个复杂的子系统。须要一个CarDriver做为外观
以简化接口。代码以下
@interface CarDriver : NSObject - (void)driveToLocation:(CGPoint)place; @end @implementation CarDriver - (void)driveToLocation:(CGPoint)place { // .... // 开启计价器 Taximeter *meter = [Taximeter new]; [meter start]; // 操做车辆,直到到达位置place Car *car = [Car new]; [car releaseBrakes]; [car changGears]; [car pressAccelerator]; // .... // 到达位置place,停下车和计价器 [car releaseAccelerator]; [car pressBrakes]; [meter stop]; // .... } @end
CarDriver的外观方法决定了客户端能够用多简单的方式使用整个出租车服务系统。客户只需调用driveToLocation:方法,其他的操做就会在消息调用中发生。客户端不须要了解底层发生的一切。
经过上面的讲解,咱们来分析一下外观模式的特色:
Facade设计模式注重从架构的层次去看整个系统,而不是单个类的层次。不少时候,它是一种架构设计模式,好比咱们经常使用的三层架构。
Facade模式简化了整个系统的接口,同时对于系统内部(子系统)与外部程序(Client)来讲,也达到了一种“解耦”的效果。
根据外观模式的特色,咱们能够在如下状况中使用Facade模式:
不须要使用一个复杂系统的全部功能,只须要使用系统的部分功能时,那么应用Façade模式提供一个高层接口将比直接调用原系统的接口简单得多。
但愿封装或者隐藏原系统的接口时,能够考虑使用外观模式。
但愿使用原系统的部分功能,并且还但愿增长一些新的功能。
构建一个具备层次结构的子系统时,使用Facade模式定义子系统中每层的高级接口。若是子系统之间是相互依赖的,你可让它们仅经过Facade进行通信,从而简化了它们之间的依赖关系。
其实这个设计模式咱们很常见,通常咱们使用第三方类的时候都会有这种模式,使用第三方时咱们只须要引用第三方的其中改一个文件就能知足不少功能的使用。我只这个文件就是讲子系统的一些方法归并到了这个文件中,从而使使用者上手更快。