由 @krq_tiger(
http://weibo.com/xmuzyq
)翻译,如果你发现有什么错误,请与我联系谢谢。
门面(Facade)模式(译者注:facade有些书籍译为门面,有些书籍译为外观,此处译为门面)
![](https://i-blog.csdnimg.cn/blog_migrate/a81e0ccacef338c044c4339b2e48a6a9.png)
门面模式针对复杂的子系统提供了单一的接口,不需要暴漏一些列的类和
API
给用户,你仅仅暴漏一个简单统一的
API
。
下面的图解释了这个概念:
这个
API
的使用者完全不需要关心背后的复杂性。这个模式非常适合有一大堆很难使用或者理解的类的情况。
门面模式解耦了使用系统的代码和需要隐藏的接口和实现类。它也降低了外部代码对内部子系统的依赖性。当隐藏在门面之后的类很容易发生变化的时候,此模式就很有用了,因为当背后的类发生变化的时候,门面类始终保持了同样的
API
。
举个例子来说,如果有一天你想取代后端服务,你不需要改变
API
的使用者,因为
API
没有发生变化。
如何使用门面模式
当前你已经用
PersistencyManager
本地保存专辑数据,使用
HTTPClient
处理远程连接,工程中的其它类暂时与本次实现的逻辑无关。
为了实现这个模式,只有
LibraryAPI
应该保存
PersistencyManager
和
HTTPClient
的实例,然后
LibraryAPI
将暴漏一个简单的
API
去访问这些服务。
注意
:
通常来说,单例类的生命周期贯穿于整个应用的生命周期中,你不应对保存太多其它对象的强引用,因为他们只有到应用关闭的时候才能被释放。
本次设计看起来像下图:
![](https://i-blog.csdnimg.cn/blog_migrate/1dc64a287e0c6ef6d3c8a56c59bc7c5e.png)
LibraryAPI
将暴漏给其它代码,但是它隐藏了
HTTPClient
和
PersistencyManager
的复杂性。
打开
LibraryAPI.h
,在文件头部增加下面的导入语句:
#import "Album.h"
接下来,在
LibraryAPI.h
中增加如下的方法定义:
- (NSArray*)getAlbums;
- (void)addAlbum:(Album*)album atIndex:(int)index;
- (void)deleteAlbumAtIndex:(int)index;
目前有一些你需要暴漏给其它类的方法。
打开
LibraryAPI.m
,增加如下的两个导入语句:
#import "PersistencyManager.h"
#import "HTTPClient.h"
这里将是唯一的导入这两个类的地方。记住:你的
API
是对于复杂系统唯一的访问点。
现在,增加通过类扩展(
class extension
)增加一些私有的变量(在
@implementation
行之上)
:
@interfaceLibraryAPI () {
PersistenceManager *persistencyManager;
HTTPClient *httpClient;
BOOL isOnline;
}
@end
isOnline
决定了是否服务器中任何专辑数据的改变应该被更新,例如增加或者删除专辑。
你现在需要通过
init
初始化这些变量。在
LibraryAPI.m
中增加如下的代码:
- (id)init{
self = [super init];
if (self) {
persistencyManager = [[PersistenceManager alloc] init];
httpClient = [[HTTPClient alloc] init];
isOnline = NO;
}
return self;
}
HTTP
客户端实际上不会真正的和一个服务器交互,它在这里仅仅是用来演示门面模式的使用,所以
isOnline
将总是
NO
。
接下来,增加如下的三个方法到
LibraryAPI.m:
-(NSArray*)getAlbums
{
return [persistencyManager getAlbums];
}
- (void)addAlbum:(Album*)album atIndex:(int)index
{
[persistencyManager addAlbum:album atIndex:index];
if (isOnline)
{
[httpClient postRequest:@"/api/addAlbum" body:[album description]];
}
}
- (void)deleteAlbumAtIndex:(int)index
{
[persistencyManager deleteAlbumAtIndex:index];
if (isOnline)
{
[httpClient postRequest:@"/api/deleteAlbum" body:[@(index) description]];
}
}
我们来看一看
addAlbum:atIndex:.
这个类首先更新本地的数据,然后如果有网络连接,它更新远程服务器。这就是门面模式的强大之处。当某些外部的类增加一个新的专辑的时候,它不知道也不需要知道背后的复杂性。
注意
:
当为子系统的类设计门面的时候,要记住:任何东西都不能阻止客户端直接访问这些隐藏的类。不要对这些防御性的代码太过于吝啬,并且也不要假设所有的客户端都会和门面一样使用你的类。
构建并运行你的应用。你将看到一个激动人心的空白的黑屏(哈哈)
:
![](https://i-blog.csdnimg.cn/blog_migrate/f3eb7a4d332ed6d1dfab336a62046cdd.png)
接下来,你将需要在屏幕上显示专辑数据,使用你的下个设计模式
-
装饰器设计模式将是非常好的选择。
原文出处:http://xmuzyq.iteye.com/blog/1942379