标签 设计模式 下的文章

访问者模式,是设计模式中最难的一种模式。访问者模式适用于数据结构相对稳定的系统。访问者模式对数据结构和作用于结构上的操作之间进行了一次解耦合。访问者模式的目的是把处理从数据结构分离出来。
访问者模式的适用场景:所开发的系统具有比较问题的数据结构,又有抑郁变化的算法。因为访问者模式使得算法操作的增加和扩展变得容易。优点是增加新的操作更加容易,因为增加新操作就是意味着增加新的访问者,访问者模式将有关的行为集中到一个对象中。缺点显而易见了,就是改变数据结构变得下个对困难。
访问者模式:表示一个作用于某对象的结构中的各个元素的操作。它使你可以在不改变各元素的前提下定义作用于这些元素的新操作。
场景:人类分为男女,对于人类这个系统,分类是非常固定的,一个元素是男,一个元素是女(人妖滚粗)。男女对同一件事情往往有不同的观点。以PHP为代码环境,模拟设计模式之访问者模式的代码实现。(暂时没有想到好的例子,就从《大话设计模式》中访问者模式摘了一段)

<?php
class Action{
    public function getManView(Man $manObj){}
    public function getWomanView(Woman $manObj){}
}
class Person{
    public function accept(Action $actionObj){}
}
class Success extends Action{
    public function getManView(Man $manObj){
        echo sprintf('%s成功时,背后多半有一个伟大的女人<br>', $manObj->getName());
    }
    public function getWomanView(Woman $womanObj){
        echo sprintf('%s成功时,背后多半有一个不成功的女人<br>', $womanObj->getName());
    }
}
class Failing extends Action{
    public function getManView(Man $manObj){
        echo sprintf('%s失败时,闷头喝酒,谁也不用劝<br>', $manObj->getName());
    }
    public function getWomanView(Woman $womanObj){
        echo sprintf('%s失败时,眼泪汪汪,谁也劝不住<br>', $womanObj->getName());
    }
}
class Love extends Action{
    public function getManView(Man $manObj){
        echo sprintf('%s恋爱时,凡事不懂也要装懂<br>', $manObj->getName());
    }
    public function getWomanView(Woman $womanObj){
        echo sprintf('%s恋爱时,凡事懂也要装不懂<br>', $womanObj->getName());
    }
}
class Man extends Person{
    private $name = '男人';
    public function getName(){
        return $this->name;
    }
    public function accept(Action $actionObj){
        $actionObj->getManView($this);
    }
}
class Woman extends Person{
    private $name = '女人';
    public function getName(){
        return $this->name;
    }
    public function accept(Action $actionObj){
        $actionObj->getWomanView($this);
    }
}
class ObjectStructure{
    private $elementList;
    public function add(Person $elementObj){
        $this->elementList[] = $elementObj;
    }
    public function display(Action $visitorObj){
        foreach($this->elementList as $element){
            $element->accept($visitorObj);
        }
    }
}
//客户端/接口
$o = new ObjectStructure();
$o->add(new Man());
$o->add(new Woman());

$successObj = new Success();
$o->display($successObj);

$failingObj = new Failing();
$o->display($failingObj);

$loveObj = new Love();
$o->display($loveObj);

这里用到一个双分派技术。客户端将状态(成功、失败、恋爱)作为参数传递给男人,这是第一次分派。男人类调用作为参数的“具体状态中的方法-男人的观点”,同时将自身传递给状态的对象,这是第二次分派。双分派意味着得到执行的操作决定于请求的种类和两个接收者的类型。双分派的好处是,如果要增加结婚类,只需要增加如下:

class Marry extends Action{
    public function getManView(Man $manObj){
        echo sprintf('%s结婚时,有妻徒刑<br>', $manObj->getName());
    }
    public function getWomanView(Woman $womanObj){
        echo sprintf('%s结婚时,婚姻保险<br>', $womanObj->getName());
    }
}

除此之外,客户端在需要的时候调用即可。不需要动其他的代码,增加新算法,只需要扩展一个新类。完美体现开放-封闭原则。

解释器模式,作为PHPer应该非常非常非常熟悉的一种,尽管不知道它叫做解释器模式,但是肯定使用过它。在解释器模式的最佳应用,就是大量优秀的模板引擎。解释器模式解决了一种特定的类型的问题发生的频率足够高,那么就可能值得将该问题的各个势力表述为一个简单的语言中的句子。这就构建了一个解释器,解释器他哦各国解释这些句子来解决问题。
解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
比如:模板引擎smart;比如论坛的UBB代码,就是用[url=http://www.lanecn.com]LaneBlog[/url]来表示<a href="http://www.lanecn.com/>LaneBlog</a>;还比如正则表达式等
场景:a表示你,b表示好,c表示世界。1表示我说,2表示你说。以PHP为代码环境,模拟设计模式之解释器模式的代码实现。

<?php
class Content{
    private $content = '';
    public function get(){
        return $this->content;
    }
    public function set($content){
        $this->content = $content;
    }
}
class Expression{
    public function interpret($contentObj){
        $content = $contentObj->get();
        if(!empty($content)){
            $lenth = strlen($content);
            for($i=0; $i<$lenth; $i++){
                if(is_numeric($content[$i])){
                    Number::excute($content[$i]);
                }else if(is_string($content[$i])){
                    String::excute($content[$i]);
                }
            }
        }
    }
}
class Number{
    public static function excute($value){
        $data = '';
        switch($value){
            case 1:
                $data = '我说:';
                break;
            case 2:
                $data = '你说:';
                break;
            default:
                break;
        }
        echo $data;
    }
}
//a表示你,b表示好,c表示世界。1表示我说,2表示你说
class String{
    public static function excute($value){
        $data = '';
        switch($value){
            case 'a':
                $data = '你';
                break;
            case 'b':
                $data = '好';
                break;
            case 'c':
                $data = '世界';
                break;
            default:
                break;
        }
        echo $data;
    }
}
//客户端/接口
$contentObj = new Content();
$str = '1abc';
$contentObj->set($str);
echo '解密' . $str . ':<br>';
$expression = new Expression();
$expression->interpret($contentObj);
echo '<br>';
$str = '2abc';
$contentObj->set($str);
echo '解密' . $str . ':<br>';
$expression = new Expression();
$expression->interpret($contentObj);

享元模式解决了大量几乎相似的对象的这种情况。设计模式中的享元模式使程序运行时更加节省服务器资源。享元模式是一种非常好的设计模式。如果一个应用程序使用了大量的对象,而大量的这些对象对服务器资源造成了很大的开销和压力时,就应该考虑使用享元模式。
享元模式:运用共享技术有效的支持大量的细粒度对象。
比如:围棋只有黑白两种棋子,用一个对象生成黑棋子,一个对象生成白棋子,是要一份代码共享给所有的黑棋子共同使用呢,还是每个黑棋子独立一个对象。这就是享元模式,共享对象以达到节省开销的目的。
场景:阿里云旗下的万网提供快速建站的服务,它是给每个用户独立生成一个网站所有的源代码,还是说同类型的网站共享一份代码?答案是后者(示例仅为说明享元模式,并不代表万网的真实实现方式)。以PHP为代码环境,模拟设计模式之享元模式的代码实现。

<?php
class User{
    private $name;
    public function __construct($name){
        $this->setName($name);
    }
    public function setName($name){
        $this->name = $name;
    }
    public function getName(){
        return $this->name;
    }
}
abstract class Website{
    private $name;
    public function __construct($name){
        $this->setName($name);
    }
    public function setName($name){
        $this->name = $name;
    }
    public function getName(){
        return $this->name;
    }
}
class ConcreteWebsite extends Website{
    public function __construct($name){
        parent::__construct($name);
    }
    public function useWebsite($userObj){
        echo '网站名称:' . $this->getName() . '。 所属用户' . $userObj->getName() . '<br>';
    }
}
class WebsiteFactory{
    private $userWebsiteList = array();
    public function getWebsite($key, $name){
        if(!isset($this->userWebsiteList[$key])){
            $this->userWebsiteList[$key] = new ConcreteWebsite($name);
        }
        return $this->userWebsiteList[$key];
    }
}
//客户端/接口
//网站工厂
$websiteFactory = new WebsiteFactory();

//采用万网提供的第一套模板并起名
$website = $websiteFactory->getWebsite('1', 'LaneBlog');
$website->useWebsite(new User('小轩'));

//采用万网提供的第一套模板并起名
$website = $websiteFactory->getWebsite('1', 'Lane博客');
$website->useWebsite(new User('小明'));

//采用万网提供的第一套模板并起名
$website = $websiteFactory->getWebsite('1', 'LixuanBlog');
$website->useWebsite(new User('小红'));

//采用万网提供的第二套模板并起名
$website = $websiteFactory->getWebsite('2', '论坛');
$website->useWebsite(new User('小白'));

根据结果可以看到,多个用户,前三个用户使用的是同一套系统。节省开销。至于名称,从库里读出来即可。这里完全不需要。

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