php设计模式简单解析

装饰器模式

扩展类的原有方法,不需要继承重写,在方法的开始和结尾增加预处理方法

前言

装饰器的思想就是方便对一个方法进行扩展,就和web框架中提供的 beforeActionafterAction 一样

  1. 装饰模式,可以动态的添加修改类的功能
  2. 一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个之类继承它,并重新实现类的方法
  3. 使用装饰模式,仅需在运行时添加一个装饰对象即可实现,可以实现最大的灵活性

    实现(例子)

  4. 定义一个装饰器接口,定义要实现的方法

  5. 创建一个对象实现装饰器的接口
  6. 在指定类中使用装饰器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    //定义装饰器接口
    interface DrawDecorator
    {
    function beforeDraw();
    function afterDraw();
    }
    //创建装饰器,实现装饰器接口
    class ColorDrawDecorator implements DrawDecorator
    {
    protected $color;
    function __construct($color = 'red')
    {
    $this->color = $color;
    }
    function beforeDraw()
    {
    echo "<div style='color: {$this->color};'>";
    }
    function afterDraw()
    {
    echo "</div>";
    }
    }
    //使用装饰器
    class Canvas
    {
    protected $decorators = array();
    //添加装饰器
    function addDecorator(DrawDecorator $decorator)
    {
    $this->decorators[] = $decorator;
    }
    //调用方法之前先调用装饰器的方法
    function beforeDraw()
    {
    foreach($this->decorators as $decorator)
    {
    $decorator->beforeDraw();
    }
    }
    // 调用方法之后调用装饰器的方法
    function afterDraw()
    {
    // 倒序一下数组,保持好顺序
    $decorators = array_reverse($this->decorators);
    foreach($decorators as $decorator)
    {
    $decorator->afterDraw();
    }
    }
    //此方法使用装饰器的方法
    function draw()
    {
    // 执行自己代码之前调用
    $this->beforeDraw();
    foreach($this->data as $line)
    {
    foreach($line as $char)
    {
    echo $char;
    }
    echo "<br />\n";
    }
    // 执行自己代码之后调用
    $this->afterDraw();
    }
    }

观察者模式

解耦利器。就是一个事件机制,我(们)先告诉你我(们)关注这件事(注册),如果这件事发生了改变(触发),通知我,我再执行我的逻辑

前言

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

实现(例子)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//事件产生者 抽象类
EventGenerator.php
abstract class EventGenerator{
private $obserers = array();
//为事件添加观察者
function addObsever(Observer $observer){
$this->obserers[] = $observer;
}
//通知观察者 调用观察者响应的方法
function ontify(){
foreach ($this->obserers as $observer){
$observer->update();
}
}
}
//事件
event.php
class Event extends EventGenerator{
function trigger(){
echo "Event <br>";
$this->ontify();
}
}
//观察者接口,定义要实现的被触发的方法
Observer.php
interface Observer{
function update($event_info = null);
}
//观察者1
Observer1.php
class Observer1 implements Observer{
function update($event_info = null){
echo "逻辑1";
}
}
……
……
//使用
index.php
$event = new Event();
$event->addObsever(new Observer1());
$event->addObsever(new Observer2());
$event->addObsever(new Observer3());
$event->trigger();

总结

和yii框架提供的事件机制原理一样

适配器模式

多个相同功能目的的类,通过相同的方法来实现相同的功能目的

前言

适配器就是为了解决兼容,或者说是为了统一接口。比较常见的是数据库的适配,因为不同的数据库提供的接口(如:增删改)是不太一样的(或者是对同样的数据库有不同的操作接口,如mysql、mysqli,pdo3),这时候为了操作的方便,我们是需要用统一的方法对不同的数据库接口进行封装。还有比较常见的是对支付方式(微信、支付宝等)的封装。类似的场景还有cache缓存适配器,将memcache、redis、file等不同的缓存方式封装成相同的操作方法

实现(例子)

  1. 定义一个定义了约定要实现的方法的接口
  2. 不同的类实现这个接口,来各自完成自己的实现相应方法的逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//定义接口
interface IDatabase
{
function connect($host, $user, $passwd, $dbname);
function query($sql);
function close();
}
//不同的数据库实现此接口
#mysqli
class MySQLi implements IDatabase
{
protected $conn;
function connect($host, $user, $passwd, $dbname)
{
$conn = mysqli_connect($host, $user, $passwd, $dbname);
$this->conn = $conn;
}
function query($sql)
{
return mysqli_query($this->conn, $sql);
}
function close()
{
mysqli_close($this->conn);
}
}
#pdo
class PDO implements IDatabase
{
protected $conn;
function connect($host, $user, $passwd, $dbname)
{
$conn = new \PDO("mysql:host=$host;dbname=$dbname", $user, $passwd);
$this->conn = $conn;
}
function query($sql)
{
return $this->conn->query($sql);
}
function close()
{
unset($this->conn);
}
}

总结

使对不同类型的操作变的相当方便,不用花费太多的时间来记录不同类型的不同方法。不需要关注太多细节,操作mysql和操作mongo的方法变的基本一致,方便。

策略模式

前言

策略模式定义了一族相同类型的算法,算法之间独立封装,并且可以互换代替。
这些算法是同一类型问题的多种处理方式,他们具体行为有差别。
每一个算法、或说每一种处理方式称为一个策略。
在应用中,就可以根据环境的不同,选择不同的策略来处理问题。

实现(例子)

实现和适配器模式相似:

  1. 定义一个定义了约定要实现的方法的接口
  2. 不同的策略类实现这个接口,来各自完成自己的实现相应方法的逻辑

以数组输出为例。
数组的输出有序列化输出、JSON字符串输出和数组格式输出等方式。
每种输出方式都可以独立封装起来,作为一个策略。
应用时,如要把数组保存到数据库中,可以用序列化方式输出。
要提供给APP作接口,可以用JSON字符串输出。
其他程序调用,则直接输出数组格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
* 策略接口
*/
interface OutputStrategy
{
public function render($array);
}
/**
* 策略类1:返回序列化字符串
*/
class SerializeStrategy implements OutputStrategy
{
public function render($array)
{
return serialize($array);
}
}
/**
* 策略类2:返回JSON编码后的字符串
*/
class JsonStrategy implements OutputStrategy
{
public function render($array)
{
return json_encode($array);
}
}
/**
* 策略类3:直接返回数组
*/
class ArrayStrategy implements OutputStrategy
{
public function render($array)
{
return $array;
}
}
/**
* 环境角色类
*/
class Output
{
private $outputStrategy;
// 传入的参数必须是策略接口的子类或子类的实例
public function __construct(OutputStrategy $outputStrategy)
{
$this->outputStrategy = $outputStrategy;
}
public function renderOutput($array)
{
return $this->outputStrategy->render($array);
}
}
/**
* 客户端代码
*/
$test = ['a', 'b', 'c'];
// 需要返回数组
$output = new Output(new ArrayStrategy());
$data = $output->renderOutput($test);
// 需要返回JSON
$output = new Output(new JsonStrategy());
$data = $output->renderOutput($test);

总结

策略模式和适配器模式有什么不一样

注册树模式

把创建的对象存放在一个对象中,将来访问的时候直接从这个对象中获取

前言

创建一个注册器类,将创建的对象绑定到注册树上,之后可以在全局通过注册树类进行访问绑定过的对象
其实可以实现单利模式的目的,即创建一次,全局使用;

实现(例子)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 注册树类
*/
class Register
{
protected static $objects;
//通过别名的方式,将对象绑定到注册树上
static function set($alias, $object)
{
self::$objects[$alias] = $object;
}
//通过别名获取对象
static function get($alias)
{
return self::$objects[$alias];
}
//销毁
static function _unset($alias)
{
unset(self::$objects[$alias]);
}
}

参考

歪麦博客(UML类图的使用,php设计模式)
慕课网-php设计模式
设计模式

echo-ding wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!