设计模式之(七)外观模式(门面模式、过程模式)

本文首发于个人博客

前言

什么是外观模式

外观模式 属于结构型模式,在菜鸟教程中的定义如下

外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。

这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。

模式结构

介绍

意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

主要解决:

降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。

何时使用:

  • 客户端不需要知道系统内部的复杂联系,整个系统只需提供一个”接待员”即可。
  • 定义系统的入口。

如何解决:

客户端不与系统耦合,外观类与系统耦合。

关键代码:

在客户端和复杂系统之间再加一层,这一层将调用顺序、依赖关系等处理好。

应用实例:

  • 去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待人员,只让接待人员来处理,就很方便。
  • JAVA 的三层开发模式。

使用场景:

  • 为复杂的模块或子系统提供外界访问的模块。
  • 子系统相对独立。
  • 预防低水平人员带来的风险。

注意事项:

在层次化结构中,可以使用外观模式定义系统中每一层的入口。

代码

场景

每天到公司开电脑,下班离开公司关电脑。而每次开电脑之后,都要打开Xcode、微信、QQ等等。而每次关电脑的时候,这些软件又会依次关闭。所以我们可以把这些设置为开机自启动。那么,每次开机的时候,只需要开电脑就行了,其他的我们不用关心,能自动开启。

YZComputer

创建YZComputer类,给外界两个接口,分别是open和close

1
2
3
4
5
6
7
8
9
10
11
#import <Foundation/Foundation.h>
#import "YZQQ.h"
#import "YZWeChat.h"
#import "YZXcode.h"

@interface YZComputer : NSObject

-(void)close;
-(void)open;

@end
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
#import "YZComputer.h"

@interface YZComputer()
@property (strong, nonatomic) YZQQ * qq;
@property (strong, nonatomic) YZWeChat * weChat;
@property (strong, nonatomic) YZXcode * xcode;
@end

@implementation YZComputer

- (instancetype)init
{
self = [super init];
if (self) {
self.qq = [[YZQQ alloc] init];
self.weChat = [[YZWeChat alloc]init];
self.xcode = [[YZXcode alloc]init];
}
return self;
}

-(void)close{
NSLog(@"%s",__func__);
[self.qq close];
[self.weChat close];
[self.xcode close];
}
-(void)open{
NSLog(@"%s",__func__);
[self.qq open];
[self.weChat open];
[self.xcode open];
}
@end

YZQQ

1
2
3
4
5
6
7
8
9
10
11
#import <Cocoa/Cocoa.h>

NS_ASSUME_NONNULL_BEGIN

@interface YZQQ : NSObject
-(void)close;
-(void)open;

@end

NS_ASSUME_NONNULL_END
1
2
3
4
5
6
7
8
9
10
#import "YZQQ.h"

@implementation YZQQ
-(void)close{
NSLog(@"%s",__func__);
}
-(void)open{
NSLog(@"%s",__func__);
}
@end

YZWeChat

1
2
3
4
5
6
7
8
9
10
11
#import <Cocoa/Cocoa.h>

NS_ASSUME_NONNULL_BEGIN

@interface YZWeChat : NSObject
-(void)close;
-(void)open;

@end

NS_ASSUME_NONNULL_END
1
2
3
4
5
6
7
8
9
10
#import "YZWeChat.h"

@implementation YZWeChat
-(void)close{
NSLog(@"%s",__func__);
}
-(void)open{
NSLog(@"%s",__func__);
}
@end

YZXcode

1
2
3
4
5
6
7
8
9
10
11
#import <Cocoa/Cocoa.h>

NS_ASSUME_NONNULL_BEGIN

@interface YZXcode : NSObject
-(void)close;
-(void)open;

@end

NS_ASSUME_NONNULL_END
1
2
3
4
5
6
7
8
9
10
#import "YZXcode.h"

@implementation YZXcode
-(void)close{
NSLog(@"%s",__func__);
}
-(void)open{
NSLog(@"%s",__func__);
}
@end

优点:

  • 对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易。通过引入外观模式,客户代码将变得很简单,与之关联的对象也很少。

  • 实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。

  • 降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。

  • 只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。

缺点:

  • 外观类接口膨胀。由于子系统的接口都有外观类统一对外暴露,使得外观类的API接口较多,在一定程度上增加了用户使用成本。

  • 不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。

  • 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。

Demo地址