外观情势笔记,PHP之外观情势
分类:计算机编程

外观(Facade)模式

当使用子系统的代码时,你也许会发现自己过于深入地调用子系统的逻辑代码。如果子系统代码总是在不断变化,而你的代码却又在许多不同地方与子系统代码交互,那么随着子系统的发展,你也许会发现维护代码变得非常困难。

在项目中集成复杂的第三方代码,或在系统中逐渐形成大量仅在系统自身内部有用的代码,在这些情况下,你总可以应用外观模式,为复杂的系统创建一个简单、清晰的接口。

假设有下面一段很乱的代码,其功能是从文件中获取log信息并将它转换为对象:

function getProductFileLines($file)
{
    return file($file);
}

function getProductObjectFromID($id, $productname)
{
    // 一些数据库查询
    return new Product($id, $productname);
}

function getNameFromLine()
{
    if (preg_match("/.*-(.*)sd /"), $line, $array) {
        return str_replace('_', ' ', $array[1]);
    }
    return '';
}

function getIDFromLine($line)
{
    if (preg_match("/^(d{1,3})-/", $line, $array)) {
        return $array[1];
    }
    return -1;
}

class Product()
{
    public $id;
    public $name;
    public __construct($id, $name)
    {
        $this->id = $id;
        $this->id = $name;
    }
}

我们的目的是将包含类似下面数据的文件转换为一个对象数组:

 234-ladies_jumper 55
 532-gents_hat 44

客户端使用该功能时要调用所有的方法:

$lines = getProductFileLines('text.txt');
$objects = array();
foreach ($lines as $line) {
    $id = getIDFromLine($line);
    $name = getNameFromLine($line);
    $objects[$id] = getProductObjectFromID($id, $name);
}

如果在项目中直接调用这些方法,那么我们的代码会和子系统紧紧耦合在一起。当子系统变化时,或者我们决定将其与子系统完全断开时,代码就会出问题。

下面这个简单的类为上面的过程式代码提供了一个接口:

class ProductFacade
{
    private $products = array();

    function __construct($file)
    {
        $this->file = $file;
        $this->compile();
    }

    private function complie()
    {
        $lines = getProductFileLines($this->line);
        foreach ($lines as $line) {
            $id = getIDFromLine($line);
            $name = getNameFromLine($line);
            $this->products[$id] = getProductObjectFromID($id, $name);
        }
    }

    function getProducts()
    {
        return $this->products;
    }

    function getProduct($id)
    {
        return $this->product[$id];
    }
}

现在,从一个log文件访问Product对象就简单多了:

$facade = new ProductFacade('test.txt');
$facade->getProduct(234);

外观模式的好处:(1)对于调用者来说,访问代码变得简洁、非常方便.(2),由于只在一个地方调用子系统,减少了出错的可能.(3),Facade类还能使调用者避免不正确地使用内部方法,从而减少错误的发生。

注1:这是《深入PHP:面对对象、模式与实践》第十章的部分内容(其他的都看不懂,逃~)
注2:此文章也可以在我单独的博客里面看到:

文摘一:
有些地方外观模式也被叫做门面模式,英文即Facade Pattern,提前说明一下。

试想这种情况,用户添加了一条记录,为了保持本地和服务器数据的一致性,除了在本地数据库插入记录,还需要把该记录发送给服务器,让服务器的数据库也一并更新。

为了保持代码的可读性和低耦合性,一般会把不同的功能放在不同的文件不同的类中。如上面所说的情况,就需要一个DataHandler类更新本地数据库,还需要一个NetworkClient类处理网络请求。这两个类有如下定义:

@interface DataHandler : NSObject

- (void)addItemToDatabase:(id)item;

@end

@interface NetworkClient : NSObject

- (void)addItemToServer:(id)item;

@end

每当数据有变化,都需要调用这两个类的方法。如果DataHandler和NetworkClient这两个类中的方法有变化,相应的需要修改很多调用者的代码。

而采用外观模式时,一个Facade将DataHandler和HTTPClient封装在一起,然后提供一个新的接口。 现在定义一个Manager类如下:

@interface Manager : NSObject

- (void)addItem:(id)item;

@end

@implementation Manager
{
    DataHandler *dataHandler;
    NetworkClient *networkClient;
}

- (void)addItem:(id)item
{
    [dataHandler addItemToDatabase:item];
    [networkClient addItemToServer:item];
}

@end

现在每当用户添加新数据时,只需调用Manager的addItem:方法就可以实现本地和服务器数据库的操作。而且如果DataHandler类和NetworkClient类的方法有变化,也只需修改Manager中的代码,对调用者并没有影响。

外观模式本质就是一种封装,将零散的功能组合成一个,然后对外提供一个接口,使用者只需要知道这一个接口就可以了。这种模式大大降低了代码的耦合性,对代码重用和迭代开发很有帮助。

注意,在使用外观模式时,各个子模块的接口是无法被隐藏起来的,你也不能阻止调用者不使用集成的API而去单独访问各子模块接口。

文摘二:
考虑使用外观模式的情况一般分为三种情况。
第一种情况,设计初始阶段,应该要有意识的将不同的两个分层分离,层与层之间建立外观Facade,这样可以为复杂的子系统提供一个简单的接口,使得耦合大大降低。
第二种情况,在开发阶段子系统往往因为不断的重构演化而变得越来越复杂,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖。
第三种情况,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,如果有新的需求,那么可以为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作,这样可以保持较低的耦合度。

文摘三:

引言  
  在项目开发中,有时候会遇到这样的一种情景:已有系统的各个子系统之间,随着业务需求的发展,有了比较紧凑的耦合关系。现在需要利用这些子系统的功能,为移动端提供业务处理。我们该怎么应对这样的业务需求呢?这就是本章外观模式所要解决的问题。
  进入正式讲解前,我们先来分析一下两种应对如上业务需求的方式:
  方式一:移动端直接调用各个子系统的功能,和各个子系统之间形成紧耦合的关系,如下图所示:

图片 1

  方式二:提供一个高层接口,该高层接口负责和子系统进行交互,并向移动端提供需要使用的接口,如下图所示:

图片 2

  从上面两种方式的图式结构可以看到,对移动端来说,方式二比方式一要好用很多,因为在方式二中,移动端不需要知道各个子系统的逻辑,只需要和高层接口交互就可以了。实际上方式二,就是我们这里要说的外观模式了。
定义
  “为子系统中的一组接口提供一个统一的接口。外观模式定义了一个更高层次的接口,这个接口使得这一子系统更加容易使用。”
  最初的定义出现于《设计模式》(Addison-Wesley,1994)。
  这个定义,通过上面引言的图示讲解,应该很好理解了,这里再分析一下定义中的两个重要角色:
  外观角色:就是引言图示中的“高层接口”,客户端可以调用这个角色的方法;另外,该角色知道相关的子系统的功能和责任。
  子系统角色:可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。每一个子系统都可以被客户端直接调用,或者被外观角色调用。
结构图

图片 3

示例
  生活中,应用外观模式的例子很多,比如去饭馆吃饭,我们不需要关注菜的选料、烹调等过程,只需要和服务员进行交互:服务员给我们菜谱(相当于就是外观模式的高级接口),我们选菜(调用接口),就可以享受美食。
  这里,我们用另一个生活中的例子来进行解说。不知道大家有没有通过旅行社报团出去旅游的经历?这是一个很好的外观模式的应用。我们选择好景点之后,旅行社会帮我们联系大巴、旅馆、饭店、景点门票以及景点服务等事情,这些事情我们都不需要亲自去安排,这就是外观模式的便利之处:可以使得客户端的接口更简单。

  下面列出应用外观模式实现旅行社报团旅游的结构图:

图片 4

  如果不应用外观模式,我们(上图中的Client),就得自己去联系交通工具、预定旅馆、饭馆、景点门票等,相信这样的旅程,大家会感觉很累。有了外观角色(上图中的Facade),它会帮我们去处理这些事情。完整代码大家可以下载查看,这里只贴出部分源码。
  Facade.m(部分源码):

 - (id)init { 
  self = [super init]; 
  if (self != nil) { 
     _transportation = [[Transportation alloc] init]; 
     _hotel = [[Hotel alloc] init]; 
     _restaurant = [[Restaurant alloc] init]; 
     _attractions = [[Attractions alloc] init];  
   } 
   return self; 
}  

 - (void)travel {  
     [_transportation selTransportation];  
     [_hotel selHotel];  
     [_restaurant selRestaurant]; 
     [_attractions selAttractions]; 
}  

 - (void)dealloc23 {  
    [_transportation release];  
    [_hotel release];  
    [_restaurant release];  
    [_attractions release];   
    [super dealloc]; 
 }

从源码可以看到,外观类调用了交通工具类、旅馆类、饭馆类、景点类。下面看看客户端调用代码:

 Facade *facade = [[Facade alloc] init];
 [facade travel];
 [facade release];

客户端代码只需要和外观类进行交互。

小结
通过上面的讲解,我们来分析一下外观模式的特点:
Facade设计模式注重从架构的层次去看整个系统,而不是单个类的层次。很多时候,它是一种架构设计模式,比如我们常用的三层架构。
Facade模式简化了整个系统的接口,同时对于系统内部(子系统)与外部程序(Client)来说,也达到了一种“解耦”的效果。

根据外观模式的特点,我们可以在以下情况中使用Facade模式:
不需要使用一个复杂系统的所有功能,只需要使用系统的部分功能时,那么应用Façade模式提供一个高层接口将比直接调用原系统的接口简单得多。
希望封装或者隐藏原系统的接口时,可以考虑使用外观模式。
希望使用原系统的部分功能,而且还希望增加一些新的功能。
构建一个具有层次结构的子系统时,使用Facade模式定义子系统中每层的高级接口。如果子系统之间是相互依赖的,你可以让它们仅通过Facade进行通讯,从而简化了它们之间的依赖关系。

循自然之道,抚浮躁之心

http://www.cnblogs.com/eagle927183/p/3511876.html

本文由pc28.am发布于计算机编程,转载请注明出处:外观情势笔记,PHP之外观情势

上一篇:电子商务货品库的成品设计,PHP数组内容不重复 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • 电子商务货品库的成品设计,PHP数组内容不重复
    电子商务货品库的成品设计,PHP数组内容不重复
    多年来在做ecshop的货物仓库储存模块,分别给黄金年代款商品的两性情格组合设置仓库储存,如下图: # 手艺文书档案 每一天逛天猫和京东的时候,映着重
  • 九彩拼盘的前端技能,LayUI框架的应用
    九彩拼盘的前端技能,LayUI框架的应用
    内容: HTML 普及标签和总体性 文书档案类型申明 转义字符 网页访问无障碍(只是掌握卡塔 尔(阿拉伯语:قطر‎ CSS 常用采取器 体制生效准绳(浏览器的
  • 编制程序总计,动态目的
    编制程序总计,动态目的
    dynamic是FrameWork4.0的新特色。dynamic的现身让C#具备了弱语言类型的风味。编写翻译器在编写翻译的时候不再对项目举行检查,编译期暗中同意dynamic对象扶植
  • 动态编写翻译,在线运转
    动态编写翻译,在线运转
    千帆竞发产生c#代码的在线编辑。     在帮顾客写JAVA客商端访谈.NET达成的Webservice的示范代码发掘了一个有意思的标题。为有保持安全性,使用了wse2.0sp
  • 二叉树中度为2的结点
    二叉树中度为2的结点
    int Degree2(BitNode *t){ if(t==null) return 0;if(t-lchild!=nullt-rchild!=null) return 1 Degree2(t-lchild) Degree2(t-rchild);return Degree2(t-lchild) Degree2(t-rchild); } 您可能感兴趣的 非递归先