系列文章---框架篇:9.设计模式


框架的开发基本结束了,这一节我们来探讨一下设计模式。


谈设计模式,首先要来简单聊聊面向对象。

面向对象

面向对象程序设计(Object-Oriented Programming, OOP)是一种程序设计范型,同时也是一种程序开发方法。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和可扩展性。它和面向过程、函数式编程被称为编程语言中的三大范式。

概念知识

  1. 面向对象的核心思想是对象、封装、可重用性、可扩展性。
  2. 面向对象三要素:封装、继承和多态。
  3. 面向对象设计的五大原则:单一职责原则、接口隔离原则、开放封闭原则、替换原则、依赖倒置原则。

关于这些概念的更详细解释,我推荐大家阅读《PHP核心技术与最佳实践》这本书关于关于面向对象的部分。

设计模式

上述所述的面向对象知识,尤其是面向对象设计的五大原则,是诸多设计模式的基础。

设计模式有很多,我们可以简单列出来:

  1. 有强调实例化过程的创建型设计模式
  • 抽象工厂
  • 生成器
  • 工厂方法
  • 原型
  • 单例
  1. 又有组合对象和类构成更大结构的结构型设计模式
  • 适配器模式
  • 桥接模式
  • 组合模式
  • 装饰器模式
  • 外观模式
  • 享元模式
  • 代理模式
  1. 还有行为型设计模式
  • 职责链模式
  • 命令模式
  • 解释器模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 观察者模式
  • 状态模式
  • 策略模式
  • 模板授权模式
  • 访问者模式

说到这里你有没有蒙圈?

其实我们无需一下子去了解那么多设计模式,在实际开发过程中我们可能也是混合使用设计模式的。我们不妨可以就框架里用到的几个典型的设计模式做一些分析。

单例模式

是否还记得我们使用Redis代替Session那一节,我们就用到了单例模式。

我们来简化一下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class RedisSession
{
private $redis;

private function getRedisInstance()
{
if (empty($this->redis)) {
$redis = new \Redis();
$redis->connect($this->_config['host'], $this->_config['port'], $this->_config['timeout']);
if (!$this->_config['auth']) {
$redis->auth($this->_config['auth']);
}

$this->redis = $redis;
}
return $this->redis;
}
}

一般我们还会在类里面加入一个魔术方法__clone,防止实例创建后被clone

单例模式有显而易见的优点:提高可重用性,减少开销。框架里使用Redis时都可以使用此方法来获取redis,也减少redis的连接数和多次连接时间。

策略模式

还记得依赖注入那一节么,我们举例的那个Travel就是一个很好的策略模式Demo:

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
interface Travel
{
public function travelAlgorithm();
}

/**
*具体策略类(ConcreteStrategy)
*1:乘坐飞机
*/
class AirPlanelStrategy implements Travel
{
public function travelAlgorithm()
{
echo"travelbyAirPlain\r\n";
}
}

/**
*具体策略类(ConcreteStrategy)
*2:乘坐火车
*/
class TrainStrategy implements Travel
{
public function travelAlgorithm()
{
echo"travelbyTrain\r\n";
}
}

/**
*
*环境类(Context):
*用一个ConcreteStrategy对象来配置。
*维护一个对Travel对象的引用。可定义一个接口来让Strategy访问它的数据。
*算法解决类,以提供客户选择使用何种解决方案:
*/
class PersonContext
{
private $strategy = null;

public function __construct(Travel $travel)
{
$this->strategy=$travel;
}

/**
*旅行
*/
public function travel()
{
return$this->strategy->travelAlgorithm();
}

}
// 乘坐火车旅行
$person = new PersonContext(new TrainStrategy());
$person->travel();

// 改乘飞机
$person =PersonContext(new AirPlanelStrategy());
$person->travel();

策略模式降低了代码耦合度,可以使得我们下层代码依赖上层,替换下层代码即可简单实现功能的替换。

工厂方法

我们在路由解析创建控制器那里使用了工厂方法,只不过与路由解析代码糅合在一起,我们简化一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Factory
{
public function createController($controllerName)
{
$controllerName = rtrim($controllerName,'\\').'Controller';

if (!class_exists($controllerName)) {
throw new NotFoundException("未找到控制器");
}

return new $controllerName;
}

···
}

工厂方法是很常见的一种设计模式,像Model经常能用到。