分类 灵魂思想 下的文章

单例模式,顾名思义,单个的实例,就是对某个对象,只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();

迭代器模式,将一个列表从头到尾或者从尾到头进行一次遍历。迭代器模式是被提名要求废除的一种设计模式。因为很多的高级语言,如PHP,Python,JAVA等,都已经拥有了foreach。
迭代器模式:提供一种方法顺序,来访问一个聚合中的各个元素,而不暴露该对象的内部表示。
迭代器模式用来访问一个列表的第一个,最后一个,或者某一个的下一个。
以PHP为代码环境模拟一下迭代器模式的思想。抽象一个Iterator类的理由是有可能是正序,有可能倒序查找。

<?php
abstract class Iterator{
    public function first(){

    }
    public function last(){

    }
}
//正序
class PositiveOrder extends Iterator{
    private $list;
    private $listTmp;
    public function __construct($list){
        $this->list = $list;
        $this->listTmp = array_values($list);
    }
    public function first(){
        return $this->listTmp[0];
    }
    public function last(){
        return $this->listTmp[(count($this->listTmp)-1)];
    }
}
//倒序
class ReverseOrder extends Iterator{
    private $list;
    private $listTmp;
    public function __construct($list){
        $this->list = $list;
        $this->listTmp = array_values($list);
    }
    public function first(){
        return $this->listTmp[(count($this->listTmp)-1)];
    }
    public function last(){
        return $this->listTmp[0];
    }
}

我们还可以去模拟获取某个元素的下一个元素等。
在PHP中,活跃社区的各个开发者都在为PHP的明天做贡献,为我们提供了已经封装好的函数,用来操作PHP数组的内部指针。

next();    定位指针到当前位置的后一个
prev();       定位指针到当前位置的前一个
reset();   重置指针到数组的开始
end();     定位指针到数组的最后
current(); 取得当前指针位置的值
key();     取得当前指针位置的键

使用示例:

<?php
$arr=array("php"=>"脚本","python"=>"脚本","mysql"=>"数据库");
while(list($key,$value)=each($arr)){
    echo $key.'============>'.$value.'<br>';
}
/**
 * 输出结果
 * php============>脚本
 * python============>脚本
 * mysql============>数据库
 */
reset($arr);
while(list($key,$value)=each($arr)){
    echo $key.'============>'.$value.'<br>';
}
/**
 * 输出结果
 * php============>脚本
 * python============>脚本
 * mysql============>数据库
 */
reset($arr);
next($arr);
while(list($key,$value)=each($arr)){
    echo $key.'============>'.$value.'<br>';
}
/**
 * 输出结果
 * python============>脚本
 * mysql============>数据库
 */
end($arr);
echo current($arr).'=============>'.key($arr).'<br>';
/**
 * 输出结果
 * mysql============>数据库
 */
prev($arr);
echo current($arr).'=========>'.key($arr).'<br>';
/**
 * 输出结果
 * python============>脚本
 */

组合模式告诉我们,对待部分和对待整体是一样的。整体和部分就是总部和分部的关系。使用设计模式中的组合模式,客户端不需要知道它调用的到底是整体的接口还是部分的接口。北京总公司为整体,下属有上海分公司,北京总公司财务,北京总公司人事。上海分公司下属有上海分公司财务,上海分公司财务。这就是整体与部分的关系,是组合模式的使用前提。需求中是体现部分和整体的结构时,用户不需要关心是在使用整体的对象还是单个对象而是使用统一的接口对象时,就可以考虑设计模式中的组合模式了。
组合模式:可以用整体-部分的结构来表示一个对象的结构层次。使用组合模式使得用户对组合对象和单个对象没有不同的感受。
场景:北京总公司,上海分公司,北京财务部,上海财务部的公司结构。以PHP为代码环境。代码仅仅为了说明组合模式,并不推荐实际开发中的使用。

<?php
//具体的公司
class ConcreteCompany{
    public $name;
    private $companyList = array();
    public function __construct($name){
        $this->name = $name;
    }
    public function add($obj){
        $this->companyList[] = $obj;
    }
    public function display(){
        foreach($this->companyList as $company){
            echo '--';
            echo $company->name;
            echo '<br>';
            if(!empty($company->companyList)){
                echo '--';
                $company->display();
            }
        }
    }
}
class Department{
    public $name;
    public function __construct($name){
        $this->name = $name;
    }
    public function add(){
        echo '已经是最小分类了,不能再细分了<br>';
    }
    public function display(){
        echo '--';
        echo $this->name;
        echo '<br>';
    }
}
//客户端/接口
$headCompany = new ConcreteCompany('北京总公司');
$headCompany->add(new Department('北京总公司财务部'));
$headCompany->add(new Department('北京总公司人事部'));

$concreteCompany1 = new ConcreteCompany('上海分公司');
$concreteCompany1->add(new Department('上海分公司财务部'));
$concreteCompany1->add(new Department('上海分公司人事部'));
$headCompany->add($concreteCompany1);

$concreteCompany2 = new ConcreteCompany('青岛分公司');
$concreteCompany2->add(new Department('青岛分公司财务部'));
$concreteCompany2->add(new Department('青岛分公司人事部'));
$headCompany->add($concreteCompany2);

echo '全公司组织架构:<br>';
$headCompany->display();
echo '<br><br>上海分公司组织架构:<br>';
$concreteCompany1->display();
echo '<br><br>上海分公司组织架构:<br>';
$concreteCompany2->display();

备忘录模式,顾名思义,记录某种数据,在需要的时候释放出来。在游戏中,存档,读档就是备忘录模式。被Boss打死后复活,数据回复到打Boss之前,也是设计模式中的备忘录模式。在但是在游戏中,角色类的功能不能带有存储旧状态数据和恢复旧状态数据的方法。把存储和读取的细节封装到一个新类中。职责分离。每个类超过一个功能,就需要考虑拆分了。这也是单一原则的体现。
备忘录模式:在不破坏封装的前提下,捕获一个对象的内部属性数据,将这个状态保存在另一个类中,以便以后的恢复数据需求。
场景:EA知名游戏模拟人生The Sims,存档和读档。以PHP为代码环境来模拟场景。

<?php
//管理‘档案器的类’的类
class Archives{
    private $memento;
    public function get(){
        return $this->memento;
    }
    public function set($mementoObj){
        return $this->memento = $mementoObj;
    }
}
class Memento{
    private $mementoData;
    public function __construct($data){
        $this->mementoData = $data;
    }
    public function get(){
        return $this->mementoData;
    }
}
class GameRole{
    private $money;
    private $name;
    public function setMoney($money){
        $this->money = $money;
    }
    public function setName($name){
        $this->name = $name;
    }
    public function getMoney(){
        return $this->money;
    }
    public function getName(){
        return $this->name;
    }
    public function setMemento(){
        $data['money'] = $this->money;
        $data['name'] = $this->name;
        return new Memento($data);
    }
    public function getMemento($mementoObj){
        $mementoData = $mementoObj->get();;
        $this->money = $mementoData['money'];
        $this->name = $mementoData['name'];
    }
    public function display(){
        echo '玩家' . $this->name . '家有家庭资产' . $this->money . '元<br>';
    }
}
//客户端/接口
//游戏开始,小明家有100元
$playObj = new GameRole();
$playObj->setName('小明');
$playObj->setMoney(100);
$playObj->display();
//存档
$archivesObj = new Archives();
$archivesObj->set($playObj->setMemento());
//小明家做生意亏损了90元
$playObj->setMoney(10);
$playObj->display();
//读档
$playObj->getMemento($archivesObj->get());
$playObj->display();

优点:彻底封装了存档和读档的细节实现,完全不对外公开。备忘录类只有玩家类能够操作。对客户端和顶层外网接口完全细节封装和数据封闭。

适配器模式,尽管是一种常见的设计模式,但是有点亡羊补牢的感觉。不是首选的设计模式。适配器模式是连接两个类的中间件,当一个类想要调用某一个类的接口时,发现尽管这个类的接口可以实现想要的功能,但是却不能用。比如因为格式的问题等等,这时候需要一个中间件来充当转换器,这就是适配器模式。
适配器模式:适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。(本段摘自百度百科(因为想找个不是我的白话文的定义-.-))。
实际生活中,比如我们买美版、欧版的电子产品,人家很多国家时110V电压,而我们国家时220V电压,所以需要一个电源适配器,来转换电压以便能够再国内的电网环境中安全的使用。
下面的例子是一个假设,由于历史原因或者开发不规范的原因,时有些定义并不一致。比如已经离职的同事A定义了商品字符串为id|num^id|num,而另一个同事B在开发时使用的是id@num#id@num,使得第三个同事C在开发时不能直接调用A和B同事的写好的现成类的方法,需要写一个类做为中间件来转换它。使的他们兼容。开放 - 封闭原则告诉我们,不要去修改人家的类,而是以扩展的方式去改变它。因此适配器模式诞生了。以PHP为代码环境:

<?php
//id|num^id|num
class ColleagueA{
    public static function getString(){
        //读取mysql略
        return '1|1^2|1';
    }
    public static function setString($str){
        echo '写进mysql:' . $str;
    }
}
//id@num#id@num
class ColleagueB{
    public static function getString(){
        //读取mysql略
        return '1@1#2@1';
    }
    public static function setString($str){
        echo '写进mysql:' . $str;
    }
}
//适配器
class Adaptation{
    public static function changeAToB($str){
        $data = array();
        $arr = explode('^', $str);
        foreach($arr as $a){
            $data[] = explode('|', $a);
        }
        $arr = $data;
        $data = '';
        foreach($arr as $a){
            $data[] = implode('@', $a);
        }
        return implode('#', $data);
    }
    public static function changeBToA($str){
        $data = array();
        $arr = explode('#', $str);
        foreach($arr as $a){
            $data[] = explode('@', $a);
        }
        $arr = $data;
        $data = '';
        foreach($arr as $a){
            $data[] = implode('|', $a);
        }
        return implode('^', $data);
    }
}
//客户端/接口
$stringFromA = ColleagueA::getString();
$stringFromAdaptation = Adaptation::changeAToB($stringFromA);
ColleagueB::setString($stringFromAdaptation);
echo '<br>';
$stringFromB = ColleagueB::getString();
$stringFromAdaptation = Adaptation::changeBToA($stringFromB);
ColleagueA::setString($stringFromAdaptation);

Ps:严格执行开发规范,开发前该抽象的抽象,该封装的封装,比到最后没办法了用这个适配器模式强的多。
适配器模式,一种亡羊补牢的模式,食之无味,弃之可惜。