PHP常用设计模式讲解

开发中适当的使用设计模式,可以让项目有更易扩展,易维护、低耦合,代码简洁等

单例模式

<?php

/**
 * 单例模式:使类在全局范围内只允许创建一个对象,常用于数据库连接等
 */

class Singleton
{
    // 必须用private修饰,防止被外部访问
    private static $_instance = null;

    private function __construct()
    {
        // 必须用private修饰,防止被实例化
    }

    private function __clone()
    {
        // 必须用private修饰 防止被克隆
    }

    public static function getInstance()
    {
        if (empty(self::$_instance)) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }

    public function show()
    {
        echo '单例模式';
    }
}

$single = Singleton::getInstance();

$single->show();
// 单例模式

工厂模式

<?php

/**
 * 工厂模式:统一了调用对象的方式,不必要在代码需要的地方 new 一个对象
 *           避免当改变某个类的名字或者方法之后,在调用这个类的所有的代码中都修改它的名字或者参数。
 *           当一个类的名称修改后,只需要在工厂方法里修改对应的名称即可。
 */

class Database
{
    public function connect()
    {
        echo '数据库连接成功';
    }
}

class Cache
{
    public function connect()
    {
        echo '缓存开启成功';
    }
}

// 工厂模式
class Factory
{
    public static function getDatabase()
    {
        // 当Database类名称修改后,只需要需改此处代码
        return new Database();
    }

    public static function getCache()
    {
        // 当Cache类名称修改后,只需要需改此处代码
        return new Cache();
    }
}

Factory::getDatabase()->connect();
// 数据库连接成功

Factory::getCache()->connect();
// 缓存开启成功

注册模式

<?php

/**
 * 注册模式:解决全局共享对象问题
 *           将已经创建好的对象,挂到全局可以使用的数组上,在需要使用的时候,直接从该数组上获取即可,无需重新实例化
 *           tp5 框架中已体现
 */

class Register
{
    // 存储对象
    private static $_objects = [];

    // 设置对象
    public static function set($name, $object)
    {
        self::$_objects[$name] = $object;
    }

    // 获取对象
    public static function get($name)
    {
        return isset(self::$_objects[$name]) ? self::$_objects[$name] : null;
    }

    // 删除对象
    public static function delete($name)
    {
        unset(self::$_objects[$name]);
    }
}

$object = new Stdclass();

// 存储对象
Register::set('stdClass', $object);

// 获取对象
$object = Register::get('stdClass');

// $object->func() 调用对象方法

观察者模式

<?php

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

// 观察者
interface Observer
{
    public function update();
}

class Message implements Observer
{
    public function update()
    {
        // todo push message to user
        echo '给用户推送消息通知'. PHP_EOL;
    }
}

class Sms implements Observer
{
    public function update()
    {
        // todo push sms to user
        echo '给用户发送短信通知' . PHP_EOL;
    }
}

// 生产者
class OrderHandle
{
    private $_observers = [];

    /**
     * 添加观察者
     * @param Observer $observer
     */
    public function setObserver(Observer $observer)
    {
        $this->_observers[] = $observer;
    }

    public function start()
    {
        echo '订单处理开始' . PHP_EOL;
    }

    public function complete()
    {
        $this->notify();
        echo '订单处理完成' . PHP_EOL;
    }

    /**
     * 通知消费者
     */
    private function notify()
    {
        foreach ($this->_observers as $observer) {
            $observer->update();
        }
    }
}

$orderHandle = new OrderHandle();

$orderHandle->setObserver(new Message());
$orderHandle->setObserver(new Sms());

$orderHandle->start();
$orderHandle->complete();
// 订单处理开始
// 给用户推送消息通知
// 给用户发送短信通知
// 订单处理完成

策略模式

<?php

/**
 * 策略模式:将一组特定的行为和算法封装成类,以适应某些特定的上下文环境
 *           应用:社区中,根据用户性别,在广告位中展示不同的广告,男性、女性。
 */

interface Strategy
{
    public function showAd();
}

// 男性策略
class MaleStrategy implements Strategy
{
    public function showAd()
    {
        echo 'T恤,衬衫,运动裤';
    }
}

// 女性策略
class FemaleStrategy implements Strategy
{
    public function showAd()
    {
        echo '马甲,牛仔,连衣裙';
    }
}

// 用户信息
class User
{
    private $_strategy;

    public function setStrategy(Strategy $strategy)
    {
        $this->_strategy = $strategy;
    }

    public function showAd()
    {
        $this->_strategy->showAd();
    }
}

$gender = isset($_GET['gender']) ? $_GET['gender'] : 'male';
$user = new User();

if ($gender === 'female') {
    $strategy = new FemaleStrategy();
} else {
    $strategy = new MaleStrategy();
}

$user->setStrategy($strategy);
$user->showAd();
// T恤,衬衫,运动裤

适配器模式

<?php

/**
 * 适配器模式:将作用相同的不同类的不同方法封装成统一的API,对外只提供这一份api,而不管内部实现
 *             数据库操作有MySQL,MySQLi,PDO三种,可以用适配器模式统一成一致,使不同的数据库操作,统一成一致的API
 *             类似的还有Cache适配器,可以将memcache,redis,file,apc等不同的缓存函数,统一成一致的API
 */

interface IDatabase
{
    public function connect($host, $user, $password, $database);
    public function query();
}

// 自定义mysqli 避免与系统冲突
class IMysqli implements IDatabase
{
    protected $_connect = null;

    // 数据库链接
    public function connect($host, $user, $password, $database)
    {
        $mysqli = new mysqli($host, $user, $password, $database);

        if ($mysqli->connect_error) {
            die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
        }

        $this->_connect = $mysqli;
    }

    public function query()
    {
        $this->_connect->query("delete from user WHERE id = 2");
    }
}

// 自定义pdo 避免与系统冲突
class IPdo implements IDatabase
{
    protected $_connect = null;

    // 数据库链接
    public function connect($host, $user, $password, $database)
    {
        $dsn = "mysql:host={$host};dbname={$database}";

        try {
            $pdo = new PDO($dsn, $user, $password);
        } catch (PDOException $e) {
            die('Connection Error: ' . $e->getMessage());
        }

        $this->_connect = $pdo;
    }

    public function query()
    {
        $this->_connect->exec("delete from user WHERE id = 1");
    }
}

// 数据库对外提供连接的类
class Db
{
    protected $_connect = null;

    public function connect($connectType)
    {
        if ($connectType === 'mysqli') {
            $this->_connect = new IMysqli();
        } else if ($connectType === 'pdo') {
            $this->_connect = new IPdo();
        }

        return $this->_connect;
    }
}

// 系统配置采用哪种连接方式
$databaseType = 'pdo';
$db = (new Db())->connect($databaseType);

$db->connect('127.0.0.1', 'root', '123456', 'database');

// 统一查询方法,不需要关心它内部是用query实现,还是用exec 实现
$db->query();

装饰器模式

<?php

/**
 * 装饰器模式:实现对类的动态添加或修改类功能
 *             如果要在一个类中修改并添加额外的功能,通常需要一个子类来继承并重写类的方法
 *             使用装饰器模式,仅需要在运行时添加一个装饰器对象即可实现,可以实现最大额灵活性。
 */

interface Decorator
{
    // 穿着
    public function wear();
}

class Clothes implements Decorator
{
    public function wear()
    {
        echo '身穿牛仔配T恤';
    }
}

class Shoe implements Decorator
{
    public function wear()
    {
        echo '脚踏詹15';
    }
}

class Hat implements Decorator
{
    public function wear()
    {
        echo '头戴New York';
    }
}

// 被装饰类
class Person
{
    protected $_decorator = [];

    public function setDecorator(Decorator $decorator)
    {
        $this->_decorator[] = $decorator;
    }

    public function display()
    {
        echo '我的行头:';

        foreach ($this->_decorator as $decorator) {
            $decorator->wear();
        }

        echo '他们都说土';
    }
}

$person = new Person();

// 装饰衣服、鞋子、帽子,而不需要对person类进行重写,灵活搭配
$person->setDecorator(new Clothes());
$person->setDecorator(new Shoe());
$person->setDecorator(new Hat());

$person->display();
// 我的行头:
// 身穿牛仔配T恤
// 脚踏詹15
// 头戴New York
// 他们都说土

原文地址:https://www.cnblogs.com/cqingt/p/8809556.html