微信号:phpdaily

介绍:PHP在线专注于PHP编程语言学习,PHP开发经验分享,工作问题解决以及PHP在线技能测评等多功能为一体的服务系统,希望给工作学习中的PHPER带来些帮助。

PHP设计模式-工厂\/单例\/观察者模式

2018-07-16 19:53 baggee

微信公众号:PHP在线

学习设计模式的意义

1:更深入的理解面向对象的思想.

2:有利于开发出扩展性强的程序

首先看看工厂模式是什么鬼

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象

简单工厂:
<?php
/**
 * @authors BaAGee (asm19950109@hotmail.com)
 * @date    2017-09-22 08:37:00
 */


/**
 * 定义数据库接口
 */

interface DB {
    public function conn();
}

/**
 * 实现DB接口的mysql类
 */

class mysqlDB implements DB{
    public function conn(){
        echo '连接到mysql数据库';
    }
}

/**
 * 实现DB接口的sqlite类
 */

class sqLiteDB implements DB{
    public function conn(){
        echo '连接到了sqlite数据库';
    }
}

/**
 * 简单工厂模式
 */

class DBFactory{
    static $dbObj=null;

    public static function createDB($type){
        switch ($type) {
            case 'mysql':
                self::$dbObj = new mysqlDB();
                break;
            case 'sqlite':
                self::$dbObj = new sqLiteDB();
                break;
            default:
                exit('unknow $type');
        }
        return self::$dbObj;
    }
}

// 测试
$mysqlClient=DBFactory::createDB('mysql');
$mysqlClient->conn();

$sqliteClient=DBFactory::createDB('sqlite');
$sqliteClient->conn();

以上简单工厂模式代码,要是新增mongodb数据库,就要修改DBFactory类了,违反开闭原则:

1988年,勃兰特·梅耶(Bertrand Meyer)在他的著作《面向对象软件构造(Object Oriented Software Construction)》中提出了开闭原则,它的原文是这样:“Software entities should be open for extension,but closed for modification”。翻译过来就是:“软件实体应当对扩展开放,对修改关闭”。通俗的说: 添加新类/接口等进来行,修改不行.

我们就将上例中DBFactory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现,下面就是将上例中的DBFactory拓展成抽象工厂:

抽象工厂:
<?php
/**
 * @authors BaAGee (asm19950109@hotmail.com)
 * @date    2017-09-22 08:37:00
 */


/**
 * 定义数据库接口
 */

interface DB {
    // 连接数据库
    public function conn();
}

/**
 * 工厂接口
 */

interface Factory{
    // 创建数据库接口
    function createDB();
}

/**
 * 实现DB接口的mysql类
 */

class mysqlDB implements DB{
    public function conn(){
        echo '连接到mysql数据库';
    }
}

/**
 * 实现DB接口的sqlite类
 */

class sqLiteDB implements DB{
    public function conn(){
        echo '连接到了sqlite数据库';
    }
}

/**
 * 创建对应的数据库对象工厂类
 */

class mysqlFactory implements Factory{
    public function createDB(){
        return new mysqlDB();
    }
}

/**
 * 创建对应的数据库对象工厂类
 */

class sqliteFactory implements Factory{
    public function createDB(){
        return new sqLiteDB();
    }
}

////////////////////
// 假设新增MongoDB数据库 //
////////////////////

// 1:要新增mongoDB()
/**
 * 实现DB接口的mongo类
 */

class mongoDB implements DB{
    public function conn(){
        echo '连接到了mongodb数据库';
    }
}
// 2:新增对应的工厂方法
class mongoFactory implements Factory{
    public function createDB(){
        return new mongoDB();
    }
}


// 测试
$mysqlfactory=new mysqlFactory();
$mysqldb=$mysqlfactory->createDB();
$mysqldb->conn();

$sqlitefactory=new sqliteFactory();
$sqlitedb=$sqlitefactory->createDB();
$sqlitedb->conn();

$mongofactory=new mongoFactory();
$mongodb=$mongofactory->createDB();
$mongodb->conn();

这样就不违反了开闭规则了,不修改已有的代码,直接添加新的代码,提高了程序的扩展性。

单例模式:

可以保证系统中一个类只有一个实例。即一个类只有一个对象实例

class sigle{
    // 保存唯一对象
    private static $selfObj=null;
    // 目的:封锁外部new操作
    private function __construct(){}
    // 封锁外部clone
    private function __clone(){}

    public static function getObj(){
        if(self::$selfObj===null){
            self::$selfObj=new self();
        }
        return self::$selfObj;
    }
}

$q=sigle::getObj();
$w=sigle::getObj();
var_dump($q==$w);
观察者模式:

观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

实现观察者模式有很多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式。下面的图详细的描述了这样一种过程:


观察者

(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。

被观察

被观察对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者。

撤销观察

观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。

以下实例展示了安全验证和广告推送这两个观察者观察用户登录,登录后用户通知各个观察者执行自己的代码。

<?php
/**
 * @authors BaAGee (asm19950109@hotmail.com)
 * @date    2017-09-22 10:30:39
 */


// php5中提供SplObserver与被观察者SplSubject的接口

///////////////////////////////
// 定义被观察者,实现SplSubject被观察者对象 //
///////////////////////////////
class User implements SplSubject{
    // 登陆次数
    public $loginNum;
    // 用户爱好
    public $hobby;
    // 用户名字
    public $name;

    public function __construct($name,$hobby=''){
        $this->loginNum=rand(1,10);
        $this->hobby=$hobby;
        $this->name=$name;
        // 用来保存观察者的对象
        $this->observers=new SplObjectStorage();
    }

    // 用户登录入口
    public function login(){
        echo '登录成功后通知:';
        $this->notify();
    }

    // 添加观察者
    public function attach(SplObserver $observer){
        $this->observers->attach($observer);
    }

    // 删除观察者
    public function detach(SplObserver $observer){
        $this->observers->detach($observer);
    }

    /**
     * 循环遍历观察者发送通知
     */

    public function notify(){
        // 指针指向头部
        $this->observers->rewind();
        while ($this->observers->valid()) {
            // 当前观察者
            $observer=$this->observers->current();
            // var_dump($observer);
            // 传递当前用户
            $observer->update($this);
            $this->observers->next();
        }
    }
}

///////////////
// 定义安全验证观察者 //
///////////////
class Secrity implements SplObserver{
    /**
     * 本观察者通知的具体方法
     * @param  SplSubject $subject [被观察者user]
     */

    public function update(SplSubject $subject){
        if($subject->loginNum<=3){
            echo $subject->name.',这是第'.$subject->loginNum.'登录.';
        }else{
            echo $subject->name.',这是第'.$subject->loginNum.'登录,登录次数过多.';
        }
    }
}

///////////////
// 定义广告推荐观察者 //
///////////////
class Commend implements SplObserver{
    public function update(SplSubject $subject){
        if($subject->hobby=='car'){
            echo '给你推荐汽车广告'.PHP_EOL;
        }else if($subject->hobby=='php'){
            echo '推荐php培训广告'.PHP_EOL;
        }else{
            echo '好好学习,天天向上'.PHP_EOL;
        }
    }
}

// 测试
$ming=new User('小明','php');
// 添加观察者
$secrity=new Secrity();
$ming->attach($secrity);
$commend=new Commend();
$ming->attach($commend);
$ming->login();

echo '------------------------------------------------------'.PHP_EOL;

$hong=new User('小红');
// 添加观察者
$secrity=new Secrity();
$hong->attach($secrity);
$commend=new Commend();
$hong->attach($commend);
// 删除广告推荐
$hong->detach($commend);
$hong->login();

运行结果:



转载:baagee博客


 
PHP在线 更多文章 这些GIT经验够你用一年了 如何发挥出PHP7的高性能 API接口设计 PHP7.0新增功能详解 常见的 CSRF、XSS、sql注入、DDOS流量攻击
猜您喜欢 从“磕炮”“文爱”的色情交易,到被网络软色情包围的未成年人 Linux在线培训班招生介绍 从xv6 OS看文件系统的实现 Java面试中的各种类型问题(全) uCrop使用及源码浅析