首页 > Web开发 > 详细

PHP设计模式(三)

时间:2020-03-11 20:12:36      阅读:68      评论:0      收藏:0      [点我收藏+]

1)观察者模式
但一个对象发生改变时,依赖他的对象全部会受到通知,并自动更新
场景:一个事务发生后,会执行一连串更新操作。传统的编程方式,就是在事件的代码之后直接加入处理逻辑,当更新的逻辑增多之后,代码会变得难以维护,这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件主体的代码
观察者模式实现了低耦合,非侵入式的通知与更新机制

抽象类,本身没有任何代码,只有继承了他的子类,才会有逻辑

实现的例子,首先定义一个Observer的接口

Config\Observer.php

<?php

namespace Config;


interface Observer
{
    function update($event_info = null);
}

然后再定义一个EventGenerator的抽象类,Observer $observer这样的参数实际上是要传的就是一个Observer的对象,传进来的必须是一个对象,如果没有这个对象,可以直接new一个也行。然后就把所有的时间都保存进来,然后更改了方法的话,就通过notify里面,循环去通知所有的观察者的对象,这样就能实现低耦合了。

Config\EventGenerator.php

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/5/13
 * Time: 23:46
 */

namespace Config;


use Config\Observer;

abstract class EventGenerator
{
    protected $observers = array();
    function addObserver(Observer $observer){
        $this->observers[] = $observer;
    }
    function notify(){
        foreach ($this->observers as $observer) {
            $observer->update();
        }
    }
}

在index文件中测试的例子。写了两个观察者的类,然后实例化观察者接口中的update方法。然后加入观察者后,通过event里面去触发。

index.php

<?php
define(‘BASEDIR‘,__DIR__);
require_once(‘/Config/Loader.php‘);
spl_autoload_register(‘\\Config\\Loader::autoload‘);

class observer1 implements \Config\Observer
{
    function update($event = null)
    {
        echo "逻辑1\n";
    }
}
class observer2 implements \Config\Observer
{
    function update($event = null)
    {
        echo "逻辑2\n";
    }
}
class Event extends \Config\EventGenerator
{
    public function trigger(){
        echo "Event\n";
        $this->notify();
    }
}
$event = new Event();
$event->addObserver(new observer1());
$event->addObserver(new observer2());
$event->trigger();

2)原型模式
和工厂模式作用类似,都是用来创建对象
与工厂模式的实现不同,原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象,这样就免去了类创建时重复的初始化操作
原型模式适用于大对象的创建。创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可。
原型模式 这个画布是用foreach循环对长和宽进行循环的,所以如果量大的话,初始化一次需要消耗很多的资源。
使用原型模式的情况,尤其有些初始化的时候,比如还要设置颜色,长度等信息,然后用clone的话会减少资源消耗

Config\Canvas.php

<?php
namespace Config;

class Canvas
{
    public $data;
    protected $decoraters = array();

    function init($height,$wight)
    {
        $data =array();
        for ($i=0; $i<$height; $i++)
        {
            for($j=0;$j<$wight; $j++)
            {
                 $data[$i][$j]= "*";
            }
        }
        $this->data = $data;
    }

    function addDecorater(DrawDecorater $decorater)
    {
        $this->decoraters[] = $decorater;
    }

    function beforeDraw()
    {
        foreach($this->decoraters as $decorater)
        {
            $decorater->beforeDraw();
        }
    }

    function afterDraw()
    {
        $decoraters = array_reverse($this->decoraters);
        foreach($decoraters as $decorater)
        {
            $decorater->afterDraw();
        }
    }

    function draw()
    {
        $this->beforeDraw();
        foreach ($this->data as $line)
        {
            foreach ($line as $char)
            {
                echo $char;
            }
            echo "<br />\n";
        }
        $this->afterDraw();
    }

    function rect($a1,$a2,$b1,$b2)
    {
        foreach ($this->data as $k1=>$line)
        {
            if ($k1 < $a1 or $k1 > $a2) continue;
            foreach ($line as $k2=>$char)
            {
                if ($k2 < $b1 or $k2 > $b2) continue;
                $this->data[$k1][$k2] = "<span style=‘color: white‘>_</span>";
            }
        }
    }
}

//使用原型模式的情况,尤其有些初始化的时候,比如还要设置颜色,长度等信息,然后用clone的话会减少资源消耗

index.php

$t = new Config\Canvas();
$t->init(10,20);
$t->rect(3,6,4,14);
$t->draw();

echo ‘<hr/>‘;

$t2 = clone $t;
$t2->init(10,20);
$t2->rect(3,6,4,14);
$t2->draw();

 

3)装饰器模式
可以动态地添加修改类的功能
一个类提供一项功能,如果要在修改并添加额外的功能,传统的编进模式,需要写一个子类来继承他,并重新实现类的方法
使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活度

比如给上面这个画布增加颜色,传统的就是要重新写一个类去继承画布这个类,然后给他写上增加颜色的方法。
这个是装饰器模式,其实就是在所有的类调用之前,再加个before和after,这样方便插入新的功能。
其实yii2里面也有这个功能,就是那些event都会加上一个beforeevent和afterevent
实现方式:
首先针对一个类,给他加上Before和after方法,然后定义一个DrawDecorator这个接口

Config\DrawDecorator.php

<?php

namespace Config;


interface DrawDecorator
{
    //这个是装饰器模式,其实就是在所有的类调用之前,再加个before和after,这样方便插入新的功能。
    //其实yii2里面也有这个功能,就是那些event都会加上一个beforeevent和afterevent
    function beforeDraw();
    function afterDraw();
}

然后只要就可以创建SizeDrawDecorator或者ColorDrawDecorator等一系列的类来继承上面这个接口,然后实现before和after的方法。
然后再index文件中,实例化Canvas这个类,然后对其进行初始化,然后只要用addDecorator的方法来给这个类添加一个装饰器,然后传入要使用的对象,就能实现了。

index.php

//装饰器模式的使用
$canvas1 = new Config\Canvas();
$canvas1->init();
$canvas1->addDecorator(new Imooc\ColorDrawDecorator(‘green‘));
$canvas1->addDecorator(new Imooc\SizeDrawDecorator(‘10px‘));
$canvas1->rect(3, 6, 4, 12);
$canvas1->draw();

4)迭代器模式
在不需要内部实现的前提下,遍历一个聚合对象的内部元素
相比于传统的编辑模式,迭代器模式可以隐藏遍历元素的所需操作。
实现方式,先创建一个类去继承php默认的\Iterator,这个是迭代器。
然后需要实现五个接口current,next,valid,rewind,key

Config\Allstudent.php

<?php
namespace Config;

//\Iterator这个是迭代器,是php默认的
//是个接口,需要实现五个接口current,next,valid,rewind,key


class Allstudent implements \Iterator
{
    protected $ids;
    protected $data = array();
    protected $index;//迭代器的当前位置

    function __construct()
    {
        //获取数据库,然后获取所有的id
        $db = Factory::getDatabase();
        $result = $db->query("select id from student");
        $this->ids = $result->fetch_all(MYSQLI_ASSOC);
    }
    //当前的元素
    function current()
    {
        $id = $this->ids[$this->index][‘id‘];
        return Factory::getStudent($id);
    }
    //下个元素
    function next()
    {
        $this->index ++;
    }
    //当前是否还有下个元素
    function valid()
    {
        return $this->index < count($this->ids);
    }
    //重置整个迭代器
    function rewind()
    {
        $this->index = 0;
    }
    //在迭代器中的位置
    function key()
    {
        return $this->index;
    }

}

然后就可以再外面直接foreach循环然后就能拿到对应的数据,然后就可以直接操作了

index.php

$students = new \Config\AllStudent();
foreach ($students as $student)
{
    var_dump($student);
    $student->name = "test";
}

5)代理模式
在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行操作全部委派给代理对象,隐藏实体的具体实现细节。
Proxy还可以实现与代理模式分离,部署到另外的服务器,业务代码中通过RPC来委派任务。
主要的应用场景,就是mysql的主从结构,业务代码不需要修改就能进行读写分离。在proxy中对所有读的操作请求主库,然后写的操作请求从库。
传统的实现方式如下:

然后用了代理模式,就需要创建一个Proxy的类,然后在这个类中判断是执行读还是写的操作,然后分别调用不同的库来实现读写分离。

Config\Proxy.php

<?php

namespace Config;


class Proxy implements IstudentProxy
{
    function getName($id)
    {
        $db = \Config\Factory::getDb(‘slave‘);
        return $db->query("select * from student where id = {$id} ");
    }
    function setName($id,$name)
    {
        $db = \Config\Factory::getDb(‘master‘);
        return $db->query("update student set name = ‘{$name}‘ where id = {$id}");
    }

}

然后再index文件中调用的时候,这样就看不到数据的实际操作,如调用哪个库之类的信息

index.php

$db = new \Config\Proxy();
$res = $db->getName(2);
$res = $db->setName(2,‘woqu‘);

PHP设计模式(三)

原文:https://www.cnblogs.com/xiaobingch/p/12464509.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!