定义
外管设计模式是为了给子系统的一系列不同的接口提供统一的接口的方案。外观模式通过定义更高层次的接口使得子系统更容易使用,隐藏了子系统的交互细节和相互间的依赖。
简而言之,通过外观设计模式,使得原本难用复杂的一个系统变得简单易用,而这种方式就是外观模式定义了更高一层的统一接口,隐藏了原来系统调用接口以及相互间的依赖性。拿LInux的PC开机做例子,我们要说的开机不是简单的按电源键开机。其实Linux开机的具体流程大致是这样的:
- 载入BIOS的硬体资讯,并取得第一个开机装置的代号;
- 读取第一个开机装置的 MBR 的 boot Loader (亦即是 lilo, grub, spfdisk等等)的开机资讯;
- 载入Kernel作业系统核心资讯, Kernel开始解压缩,并且尝试驱动所有硬体装置;
- Kernel 执行 init程式并取得 run-level资讯;
- init 执行 /etc/rc.d/rc.sysinit档案;
- 启动核心的外挂模组 (/etc/modprobe.conf);
- init 执行 run-level的各个批次档( Scripts );
- init 执行 /etc/rc.d/rc.local档案;
- 执行 /bin/login 程式,并等待使用者登入;
- 登入之后开始以 Shell 控管主机。
其实,原来,开机是有很多步骤的,而且每个步骤不是独立的,如果我们用户自己需要去了解这个过程,恐怕没几个人会开机吧。但是,我们现在开机只要按开机键即可,一键解决了所有问题,管他什么BIOS,管他什么init,统统都可以忽略不计了。在这里,就有点类似外观设计模式了,那个电源键就是外观模式定义的更高层次的接口,而具体的开机细节则是子系统的接口了。可以看出来...外观模式确实很好用嘛。以下结构图也比较好地示范了外观模式的应用:
外观模式其实是这样定义的:
外观模式的适用场景
当出现以下情况的时候,你该考虑适用外观模式了。
- 当你的系统很复杂,涉及到很多类的时候,你该考虑使用外观模式设计为你的系统设计一个简单易用的接口了。
- 使用外观模式布局你的系统,使得每一层的子系统都有一个外观模式的接口作为入口,这样可以使得通过外观模式的接口简化子系统间的依赖。
代码示例
本例通过一个乘客搭乘出租车的例子来简示外观模式的应用。本例通过简化乘客和出租车之间的接口,使得原本很复杂的驾车过程变得简单易用,可以通过以下的结构图看看具体情况:
从上图可以看出,出租车作为一个闭合系统,包括了
CarDriver,
Taximetr和
Car三个角色,这个系统的唯一接口就是
CarDriver所定义的
driverToLocation:x,一旦你传入了参数
x,出租车司机就会把你送到x所在的地方,非常简单。但是作为出租车司机,他需要直接操作
Taximeter和
Car,司机首先需要负责
Taximeter的
start,然后接着操作
Car的
releaseBrakes、
changeGears和
pressAccelerator 启动出租车,然后通过一系列操作最后通过stop把你送到x处。整个过程非常复杂,但是对于来说,只需要跟出租车司机说,把我带到x处,即
driverToLocation:x。在这里,司机提供了一个简化了得接口,简化了复杂的开车,让乘客不需要了解任何开车的细节。这就是外观模式的魅力,真的不会为难用户,傻瓜式教学使用。上述例子中,司机是乘客和复杂系统过程的中间人,即本章所说的外观。
子系统
Car的的定义和实现:
//
// Car.h
// FacadeDemo
//
// Created by God Lin on 15/1/19.
// Copyright (c) 2015年 arbboter. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Car : NSObject
- (void) releaseBrakes;
- (void) changeGears;
- (void) pressAccelerator;
- (void) presssBrakes;
- (void) releaseAccelerator;
@end
//
// Car.m
// FacadeDemo
//
// Created by God Lin on 15/1/19.
// Copyright (c) 2015年 arbboter. All rights reserved.
//
#import "Car.h"
@implementation Car
- (void) releaseBrakes
{
NSLog(@"relase brakes");
}
- (void) changeGears
{
NSLog(@"change gears");
}
- (void) pressAccelerator
{
NSLog(@"press accelerator");
}
- (void) presssBrakes
{
NSLog(@"press brakes");
}
- (void) releaseAccelerator
{
NSLog(@"release accelerator");
}
@end
子系统Taximeter的实现和定义:
//
// Taximeter.h
// FacadeDemo
//
// Created by God Lin on 15/1/19.
// Copyright (c) 2015年 arbboter. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Taximeter : NSObject
- (void) start;
- (void) stop;
@end
//
// Taximeter.m
// FacadeDemo
//
// Created by God Lin on 15/1/19.
// Copyright (c) 2015年 arbboter. All rights reserved.
//
#import "Taximeter.h"
@implementation Taximeter
- (void) start
{
NSLog(@"start car");
}
- (void) stop
{
NSLog(@"stop car");
}
@end
外观模式定义的更高层次的接口类如下所示:
//
// CabDriver.h
// FacadeDemo
//
// Created by God Lin on 15/1/19.
// Copyright (c) 2015年 arbboter. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface CabDriver : NSObject
- (void) driveToLocation:(NSString*)x;
@end
//
// CabDriver.m
// FacadeDemo
//
// Created by God Lin on 15/1/19.
// Copyright (c) 2015年 arbboter. All rights reserved.
//
#import "CabDriver.h"
#import "Taximeter.h"
#import "Car.h"
@implementation CabDriver
// 定义高层次的接口隐藏子系统间的细节
- (void) driveToLocation:(NSString*)x
{
Car* car = [[Car alloc] init];
Taximeter* taximeter = [[Taximeter alloc] init];
[taximeter start];
[car releaseBrakes];
[car changeGears];
[car pressAccelerator];
[car releaseBrakes];
[car releaseAccelerator];
NSLog(@"Thanks, we are arrived at %@", x);
}
@end
然后客户端使用该系统直接这么做就行了:
//
// main.m
// FacadeDemo
//
// Created by God Lin on 15/1/19.
// Copyright (c) 2015年 arbboter. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "CabDriver.h"
int main(int argc, const char * argv[])
{
CabDriver* driver = [[CabDriver alloc]init];
// 通过外观模式直接简单易用的接口
[driver driveToLocation:@"大冲公交站"];
return 0;
}
我们可以发现,通过弯管模式,细节竟然隐藏的无影无踪,客户端使用该系统变得真是傻瓜式了。输出如下:
2015-01-19 22:49:45.346 FacadeDemo[18960:30525486] start car
2015-01-19 22:49:45.348 FacadeDemo[18960:30525486] relase brakes
2015-01-19 22:49:45.348 FacadeDemo[18960:30525486] change gears
2015-01-19 22:49:45.348 FacadeDemo[18960:30525486] press accelerator
2015-01-19 22:49:45.349 FacadeDemo[18960:30525486] relase brakes
2015-01-19 22:49:45.349 FacadeDemo[18960:30525486] release accelerator
2015-01-19 22:49:45.349 FacadeDemo[18960:30525486] Thanks, we are arrived at 大冲公交站
总结
如果在编程中,你发现你的系统越来越复杂,需要的类越来越多,你该可虑使用此处说的外观模式了。不然,你的即使你能够写好程序,后续的维护也是很难的,所以还是非常有必要让你的系统简化输出接口,这样事半功倍!