框架篇:9.设计模式

PHP DIY系列–一起手写一个api框架


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


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

面向对象

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

概念知识

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

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

设计模式

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

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

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

说到这里你有没有蒙圈?

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

单例模式

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

我们来简化一下代码:

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:

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();

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

工厂方法

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

class Factory
{
    public function createController($controllerName)
    {
        $controllerName = rtrim($controllerName,'\\').'Controller';

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

        return new $controllerName;
    }
    
    ···
}

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


框架篇:9.设计模式
https://blog.puresai.com/2020/02/16/phpframe12/
作者
puresai
许可协议