2014年4月

中介模式,是非常非常常见的一种设计模式。一般应用于一组对象以定义良好但是复杂的方式进行通信的场合。定制一个分布在多个类中的行为,而不像生成太多的子类。这是中介模式的应用场景。
中介模式的优点:中介类的集中化控制。
中介模式的缺点:中介类的集中化控制。
中介模式的中介类,集中化控制了所有的对象,减少了请求者和响应者的耦合。把中介封装在一个对象中,注意力从关注对象本身变成了关注它们之间的交互,更加宏观。缺点也就显而易见,因为集中化的控制,使得中介类越发的庞大,不易维护。
场景:中介抽象类联合国,中介具体类安理会。成员抽象类为国家,成员具体类为美国和伊拉克。以PHP为代码环境来描述中介模式。

<?php
<?php
abstract class UN{
    public function sentMessage($message, $countryObj){}
}
abstract class Country{
    protected $UNObj;
    public function __construct($UNObj){
        $this->UNObj = $UNObj;
    }
}
class US extends Country{
    public function __construct($UNObj){
        parent::__construct($UNObj);
    }
    public function sentMessage($message){
        $this->UNObj->sentMessage($message, $this);
    }
    public function getMessage($message){
        echo '美国收到某国消息:' . $message . '<br>';
    }
}
class Iraq extends Country{
    public function __construct($UNObj){
        parent::__construct($UNObj);
    }
    public function sentMessage($message){
        $this->UNObj->sentMessage($message, $this);
    }
    public function getMessage($message){
        echo '伊拉克收到某国消息:' . $message . '<br>';
    }
}
class UNSC extends UN{
    private $usObj;
    private $iraqObj;
    public function setUsObj($obj){
        $this->usObj = $obj;
    }
    public function setIraqObj($obj){
        $this->iraqObj = $obj;
    }
    public function sentMessage($message, $sentObj){
        if($this->usObj == $sentObj){
            $this->iraqObj->getMessage($message);
        }else{
            $this->usObj->getMessage($message);
        }
    }
}
//客户端/接口
$unsc = new UNSC();
$us = new US($unsc);
$iraq = new Iraq($unsc);
$unsc ->setUsObj($us);
$unsc->setIraqObj($iraq);
$us->sentMessage('你们不可以研发核武器!');
$iraq->sentMessage('我们没有和武器!');

职责链模式解决了请求需要经过大量的臃肿的逻辑判断,设计模式的职责链模式采用了层层上报的方式,请求发送给响应方,响应方1若不能处理,则发送给响应2,响应2若不能处理则发送给响应3...直到处理为止。职责链模式的关键是,当客户提交一个请求时,请求是沿着一个链条进行传递,直到有一个对象可以负责这个请求为止。
职责链模式:使多个对象都有机会处理请求,从而避免了请求者和响应者的耦合关系,将响应者连成一个链条,层层传递,沿着这个链条传递请求,直到可以有一个对象处理为止。
职责链的好处:请求者和响应者都没有对方的明确信息,链中的对象也不知道链的结构,结果是职责模式中的职责链可以简化对象的相互连接,降低耦合,他们只需要保存一个继承者,而不需要保存所有的继承者。在增加和修改一个请求的结构时,更加灵活。
场景:请假,组长只能批1天的请假,技术总监可以批3天的请假,3天以上需要老板亲自批示。以PHP为代码环境来描述职责链模式。

<?php
abstract class Manager{
    protected $position;
    protected $lead;
    public function getPosition(){
        return $this->position;
    }
    public function setPosition($position){
        $this->position = $position;
    }
    public function setLead($leadObj){
        $this->lead = $leadObj;
    }
}
class GroupLeader extends Manager{
    public function __construct($position){
        $this->position = $position;
    }
    public function response($day){
        if($day == 1){
            echo $this->position . '批准<br>';
        }else{
            echo $this->position . '无权处理,请示上级<br>';
            $this->lead->response($day);
        }
    }
}
class Director extends Manager{
    public function __construct($position){
        $this->position = $position;
    }
    public function response($day){
        if($day > 1 && $day <= 3){
            echo $this->position . '批准<br>';
        }else{
            echo $this->position . '无权处理,请示上级<br>';
            $this->lead->response($day);
        }
    }
}
class CEO extends Manager{
    public function __construct($position){
        $this->position = $position;
    }
    public function response($day){
        if($day > 3){
            echo $this->position . '批准<br>';
        }else{
            echo $this->position . '无权处理,请示上级<br>';
            $this->lead->response($day);
        }
    }
}
//客户端/接口
$groupLead = new GroupLeader('组长');
$director  = new Director ('总监');
$ceo = new CEO('首席执行官');
$groupLead->setLead($director);
$director->setLead($ceo);
$dayArr = array(1, 2, 3, 4, 5);
foreach($dayArr as $day){
    echo '请假' . $day . '天结果<br>';
    $groupLead->response($day);
    echo '<br><br><br>';
}

命令模式解决了行为者与请求者过于紧耦合。即命令模式将一个请求指定一个响应者的模式进行了解耦化。
命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,请求排队或记录日志已经执行可撤销的操作。
命令模式的优点:第一、比较容易的设计一个队列;第二、比较容易的命令写入日志;第三、允许接收请求的一方决定是否要否决请求;第四、比较容易的实现请求的撤销和重做;第五、增加新命令不影响其他类;第六、把请求者和响应者分离。
场景:淘宝下订单,紧耦合就是点击下单按钮,请求直接发送给响应者。使用设计模式的命令模式进行解耦操作,就是点击下订单,请求发送给一个中央订单处理系统,然后由中央订单处理系统这个中间件分发给淘宝订单中心、天猫订单中心、聚划算订单中心等不同的操作,同时添加日志记录等。以PHP为代码环境来说明命令模式。

<?php
class OrderCenter{
    public $orderList;
    public function setOrder($order){
        //没有库存
        $isStock = true;
        //秒杀活动没有开始
        $isActivityTime = true;
        if(!$isStock && !$isActivityTime){
            exit('活动没开始,即将跳转回之前的页面');
        }else{
            $this->orderList[] = $order;
        }
    }
    public function cancelOrder(){

    }
    //假定是一个队列服务
    public function queue(){
        foreach($this->orderList as $key=>$order){
            echo '订单处理成功<br>';
            $order->setOrder();
            unset($this->orderList[$key]);
        }
    }
}
class Order{
    public function buyClothes(){
        echo '购买衣服成功<br>';
    }
    public function buyShoes(){
        echo '购买鞋子成功<br>';
    }
}
abstract class Command{
    public $request;
    public function __constrcut($requestObj){
        $this->request = $requestObj;
    }
    public function setOrder(){}
}
class TaoBao extends Command{
    public function __construct($requestObj){
        parent::__constrcut($requestObj);
    }
    public function setOrder(){
        echo '淘宝订单:<br>';
        $this->request->buyClothes();
        $this->request->buyShoes();
    }
}
class Tmall extends Command{
    public function __construct($requestObj){
        parent::__constrcut($requestObj);
    }
    public function setOrder(){
        echo '天猫订单:<br>';
        $this->request->buyClothes();
        $this->request->buyShoes();
    }
}
//客户端/接口
$orderObj = new Order();
$taobaoObj = new TaoBao($orderObj);
$tmallObj = new Tmall($orderObj);
$orderCenterObj = new OrderCenter();
$orderCenterObj->setOrder($taobaoObj);
$orderCenterObj->setOrder($tmallObj);
$orderCenterObj->queue();

桥接模式,就是实现系统可能有多角度分类,每一种分类都有可能变化,可能增加或减少。那么,就把这种多角度分离出来让他们独自变化,减少它们之间的耦合。
比如,现在的智能手机,安卓的ipk文件就不能安装在苹果的ios系统上。分类一(按照手机操作系统来分):手机系统分为安卓和IOS,安卓的软件分为游戏、音乐等,IOS的软件也分为游戏、音乐等。分类二(按照软件来分):软件分为游戏和音乐,游戏分为安卓游戏和IOS游戏,音乐也分为安卓音乐和IOS音乐。
思考:增加一个手机系统,如Windos 8。那么,分类就变了。如下:分类一(按照手机操作系统来分):手机系统分为安卓和IOS和Windows 8,安卓的软件分为游戏、音乐等,IOS的软件也分为游戏、音乐等,Windows 8的软件也分为游戏和音乐等。分类二(按照软件来分):软件分为游戏和音乐,游戏分为安卓游戏和IOS游戏和Windows 8游戏,音乐也分为安卓音乐和IOS音乐和Windows 8音乐。
这种分类的弊病非常明显,如果要增加一个手机的操作系统,相应的需要改变原有分类,增加大量的class文件。操作系统和手机软件的分类是高强度耦合。
在面向对象的变成里,耦合度越高的越不利于复用,设计模式的重点就是降低耦合,减少复制-粘贴的编码模式。在这个例子中,引出了一种设计模式,叫做桥接模式。
桥接模式:将抽象的部分与它的实现分离,使他们可以独立变化。
所谓的实现,就是抽象类和派生类用来实现自己的对象。白话文就是:就是实现系统可能有多角度分类,每一种分类都有可能变化,可能增加或减少。那么,就把这种多角度分离出来让他们独自变化,减少它们之间的耦合。
桥接模式的分类:手机操作系统分为安卓和IOS,手机软件分为游戏和音乐。操作系统和软件相互独立,没有强的明显关系,操作系统和手机软件不进行分类关联,它们俩的真实关系请继续往后看。
那么,耦合度降低了,增加windows8只需要在操作系统分类下增加一个windows8,软件则不需要变化。
再引入一个原则,合成-聚合复用原则:尽量使用合成-聚合,尽量不要使用类的继承。
聚合是弱拥有关系,A可以包含B,但是B不是A的一部分。合成是强拥有关系,严格的部分和整体,两者拥有相同的生命周期。
大雁的翅膀和大雁本身是合成关系,生命周期一样,是强拥有关系。大雁和雁群是聚合关系,大雁只属于一个雁群,但是雁群不仅仅只有这一个大雁。(本例摘自《大话设计模式》)
回到上一个话题,在桥接模式的分类下,手机操作系统和手机软件之间的关系,就是聚合关系,弱的关系,才可以降低耦合。
以PHP为代码环境,说明手机的例子。

<?php
abstract class Soft{
    public function run(){}
}
class Game extends Soft{
    public function run(){
        echo '手机游戏正在运行...<br>';
    }
}
class Mp3 extends Soft{
    public function run(){
        echo '手机音乐播放器正在运行...<br>';
    }
}
abstract class OS{
    protected $softObj;
    public function setSoftObj($softObj){
        $this->softObj = $softObj;
    }
    public function run(){}
}
class Ios extends OS{
    public function run(){
        $this->softObj->run();
    }
}
class Android extends OS{
    public function run(){
        $this->softObj->run();
    }
}
//客户端/接口
echo '购买了Iphone一台,搭载IOS操作系统<br>';
$iphone = new Ios();
$iphone->setSoftObj(new Game());
$iphone->run();
$iphone->setSoftObj(new Mp3());
$iphone->run();

echo '购买了三星一台,搭载安卓操作系统<br>';
$samsung = new Ios();
$samsung->setSoftObj(new Game());
$samsung->run();
$samsung->setSoftObj(new Mp3());
$samsung->run();

单例模式,顾名思义,单个的实例,就是对某个对象,只new一次。单例模式是设计模式常见的一种,用来创建封装好的类的唯一一个实例,这样一来,可以严格控制客户怎么样访问它以及何时访问它,对唯一实例的受控访问。
单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点。
单例模式如何防止一个类被多次new呢?首先,每个类都有一个构造函数,即使没有显式的声明,也是以public存在的,将构造函数设为private。其次,让该类保存实例化后的对象,并提供一个对外的接口。
示例场景:mysql中user表。以PHP为代码环境,来模拟设计模式中的单例模式。

<?php
class UserMysqlModel{
    public function get(){
        echo '获取user表的数据<br>';
    }
    public function set(){
        echo '写入user表的数据<br>';
    }
    public function edit(){
        echo '修改user表的数据<br>';
    }
    public function del(){
        echo '删除user表的数据<br>';
    }
}
class UserBusiness{
    private static $userMysqlModelObj = '';
    private function __construct(){

    }
    public static function getInstance(){
        if(empty(self::$userMysqlModelObj)){
            self::$userMysqlModelObj = new UserMysqlModel();
        }
        return self::$userMysqlModelObj;
    }
}
//客户端/接口
$userBusinessObj = UserBusiness::getInstance()->get();
$userBusinessObj = UserBusiness::getInstance()->set();
$userBusinessObj = UserBusiness::getInstance()->edit();
$userBusinessObj = UserBusiness::getInstance()->del();