当前位置:Gxlcms > PHP教程 > PHP常用设计模式单例,工厂,观察者,责任链,装饰,策略,适配,桥接模式

PHP常用设计模式单例,工厂,观察者,责任链,装饰,策略,适配,桥接模式

时间:2021-07-01 10:21:17 帮助过:5人阅读

// 多态, 在JAVA中是这样用的, 其实在PHP当中可以自然消除, 因为参数是动态的, 你传什么过来都可以, 不限制类型, 直接调用类的方法
abstract class Tiger {
    public abstract function climb();
}

class XTiger extends Tiger {
    public function  climb() {
        echo '摔下来';
    }
}

class MTiger extends Tiger {
    public function climb() {
        echo '爬到树顶';
    }
}

class Client {
    public static function call(Tiger $animal) {
        $animal->climb();
    }
}

Client::call(new XTiger());
Client::call(new MTiger());
// 面向对象里面有一个面向接口开发, 就是一个共同的规格, 你生产插座, 我生产插头

// 共同接口
interface db {
    function conn();
}

// 服务端开发(不知道将会被谁调用)
class dbmysql implements db{
    public function conn() {
        echo '连上了MySQL';
    }
}

class dbsqlite implements db{
    public function conn() {
        echo '连上了sqlite';
    }
}

// 客户端, 看不到dbmysql, dbsqlite的内部细节的, 只知道上两个类实现了db接口.

$db = new dbmysql();
$db->conn();          // 因为知道这个类实现了db接口, 所以知道有这个conn类

$sqlite = new dbsqlite();
$sqlite->conn();

// 我连我有哪些类我都不希望告诉客户端, 那么怎么进一步进行封装
// 发生连接的双方知道的越少越好, 你还知道我有两个类
// 简单工厂

// 面向对象里面有一个面向接口开发, 就是一个共同的规格, 你生产插座, 我生产插头

// 共同接口
interface db {
    function conn();
}

// 服务端开发(不知道将会被谁调用)
class dbmysql implements db{
    public function conn() {
        echo '连上了MySQL';
    }
}

class dbsqlite implements db{
    public function conn() {
        echo '连上了sqlite';
    }
}

// 简单工厂
class Factory {
    public static function createDB($type) {
        if($type == 'mysql') {
            return new dbmysql();
        } elseif ($type=='sqlite') {
            return new dbsqlite();
        } else {
            throw new Exception("Error db type", 1);
        }
    }
}

// 客户端现在不知道对方到底有哪些类名了
// 只知道对方开放了一个Factory::createDB方法
// 方法允许传递数据库名称

$mysql = Factory::createDB('mysql');
$mysql->conn();

$sqlite = Factory::createDB('sqlite');
$sqlite->conn();

// 原本你知道服务器端的两个类名, 觉得你知道的太多, 再封装起来, 只给一个通道, 更好的适应变化
// 如果以后新增oracle类型, 怎么办?
// 我们PHP随手改了就行, 像JAVA打包一次很麻烦, 又要修改服务端内容
// 服务端要修改Factory的内容(在java, c++中, 改后还得再编译)
// 这个时候就想如何来改进呢
// 在OOD(面向对象设计)的法则中, 有重要的开闭原则--对于修改是封闭的, 对于扩展是开放的.
// 你可以新增一个源代码, 不要修改旧的代码

//现在用第二种办法, 叫工厂方法
// 共同接口
interface db {
    function conn();
}

interface Factory {
    function createDB();
}

// 服务端开发(不知道将会被谁调用)
class dbmysql implements db{
    public function conn() {
        echo '连上了MySQL';
    }
}

class dbsqlite implements db{
    public function conn() {
        echo '连上了sqlite';
    }
}

class mysqliFactory implements Factory{
    public function createDB() {
        return new dbmysql();
    }
}

class sqliteFactory implements Factory {
    public function createDB() {
        return new dbsqlite();
    }
}

// 服务器端添加oracle类
// 前面的代码不用改
// 我就新增一个数据库驱动类和一个工厂, 这样就避免了对源代码的修改
class dboracle implements db {
    public function conn() {
        echo '连接上了oracle';
    }
}

class oracleFactory implements Factory {
    public function createDB() {
        return new dboracle();
    }
}


// 客户端开始, 对方给了两个api, 一个db的api, 一个是创造数据库的api
$fact = new mysqliFactory();
$db = $fact->createDB();
$db->conn();

$fact = new sqliteFactory();
$db = $fact->createDB();
$db->conn();
// 单例
// 一般来说一个中小型网站一个db去连接数据库就行了
// 想想, 能不能只有一个db类, 一个upload类, 一个cookie类
// 类肯定只有一个, 如何保证类的实例也只有一个

// 2个对象是同一个的时候才全等

// 单例模式

class single {
    protected static $ins = null;

    // 控制权限, 封锁new操作, 把大门关上了, 需要留一个小窗户
    // 方法前加final, 则方法不能被覆盖, 类前加final, 则类不能被继承
    final protected function __construct() {}
    // 防clone
    final protected function __clone(){}
    
    //留一个接口来new对象
    public static function getIns() {
        if(self::$ins == null) {
            self::$ins = new self();
        }
        return self::$ins;
    }
}

$s1 = single::getIns();
$s2 = single::getIns();

if ($s1 === $s2) {
    echo '是一个对象';
} else {
    echo '不是一个对象';
}




    colour_blue
    
    
    
    
    



    

面向过程, 不用任务来切换

我是内容 我是广告 学习
.html




    colour_blue
    
    
    
    



责任链模式举报过程

.php power) { echo '版主删贴'; } else { $top = new $this->top; $top->process($lev); } } } class admin { protected $power = 2; protected $top = 'police'; public function process($lev) { if($lev <= $this->power) { echo '管理员封账号'; } else { $top = new $this->top; $top->process($lev); } } } class police { protected $power; protected $top = null; public function process($lev) { echo '抓起来'; } } $lev = $_POST['jubao']+0; $judge = new board(); $judge->process($lev);
.html




    colour_blue
    
    
    
    



面向过程完成举报过程

.php process(); } elseif($lev==2) { $judge = new admin(); $judge->process(); } elseif($lev==3) { $judge = new police(); $judge->process(); } // 处理的不够优雅, 现在还是面向过程的写法, 面向过程和面向对象混合了 // 如果以后在两个等级中间要添加一个等级应该怎么办
.html




    colour_blue
    
    
    
    



策略模式 和工厂方法的区别只是在逻辑上的区别, 也叫聚合

.php calc = new $calc(); } public function calc($op1, $op2) { return $this->calc->calc($op1, $op2); } } $type = $_POST['op']; $cmath = new CMath($type); echo $cmath->calc($_POST['op1'], $_POST['op2']);
// 装饰器模式 decorator

class article {
    protected $content;

    public function __construct($content)
    {
        $this->content = $content;
    }

    public function decorator() {
        return $this->content;
    }
}

$art = new article("好好学习");
echo $art->decorator();

// 文章需要小编加摘要

class BianArticle extends article {
    public function summary() {
        return $this->content.'小编加了摘要';
    }
}

$art = new BianArticle('好好学习');
echo $art->summary();

// 又请了SEO人员, 要对文章进行description处理...
class SEOArticle extends BianArticle {
    public function seo() {
        //...
    }
}

// 又有了广告部
class ADArticle extends  SEOArticle {
    // 层次越来越深, 目的却只是给文章加各种内容
}
// 装饰器模式做文章修饰功能

class BaseArt {
    protected $content;
    protected $art;

    public function __construct($content) {
        $this->content = $content;
    }

    public function decorator() {
        return $this->content;
    }
}

//编辑文章摘要

class BianArt extends BaseArt {
    public function __construct(BaseArt $art) {
        $this->art = $art;
    }
    public function decorator() {
        return $this->content = $this->art->decorator() . '小编摘要';
    }
}

// SEO
class SEOArt Extends BaseArt {
    public function __construct(BaseArt $art) {
        $this->art = $art;
    }
    public function decorator() {
        return $this->content = $this->art->decorator() . 'SEO关键词';
    }
}

$b = new SEOArt(new BianArt(new BaseArt('天天向上')));
echo $b->decorator();

$b = new BianArt(new SEOArt(new BaseArt('天天向上')));
echo $b->decorator();

// 装饰的先后顺序可以随便换, 新增多少个装饰者都很方便

// 基类负责创建对象
// 子类负责装饰
// 适配器模式

// 服务器端代码
class weather {
    public static function show() {
        $today = [
            'tep' => 28,
            'wind' => 7,
            'sun' => 'sunny',
        ];
        return serialize($today);
    }
}

// 客户端调用

$weather = unserialize(weather::show());
echo '温度: ',$weather['tep'],'
'; echo '风力: ',$weather['wind'],'
'; echo 'sun: ',$weather['sun'],'
'; // 来了一批手机上的java客户端 , 不认识PHP的串化行后的字符串, 怎么办? // 把服务器端代码改了? 旧的客户端会受影响 // 旧的类和函数都不让修改, 如何来进行扩展 // 增加一个适配器 class AdapterWeather extends weather { public static function show() { //拿到旧数据 $today = parent::show(); // 然后开始转换 $today = unserialize($today); $today = json_encode($today); return $today; } } // ==== java, python再来调用就不怕了, 通过适配器调用 $weather = AdapterWeather::show(); $w = json_decode($weather); echo '温度: ',$w->tep,'
'; echo '风力: ',$w->wind,'
'; echo 'sun: ',$w->sun,'
'; // 没有修改旧的方法, 这样就没有影响旧的客户端 // 没有修改旧的类, 说明没有违反开闭原则
// 桥接模式 bridge 尝试

// 论坛给用户发信息, 可以是站内短信, email, 手机

// 本来只需要发站内短信, 后来又需要发email
// 一个类只做一件事, 我们把他做成一个接口或者抽象类, 具体的发送由具体的子类实现

interface msg {
    public function send($to, $content);
}

class zn implements msg {

    public function send($to, $content)
    {
        echo '站内信给', $to, ' 内容是: ', $content;
    }
}

// 有一天要改造, 要发email
class email implements msg {

    public function send($to, $content)
    {
        echo 'email给', $to, ' 内容是: ', $content;
    }
}

// 后来要发短信
class sms implements msg {

    public function send($to, $content)
    {
        echo '短信给', $to, ' 内容是: ', $content;
    }
}

// 后来内容也丰富了, 分普通, 加急, 特急
// 子类就爆炸了, 像数据的三范式一样, 如果完全遵循解耦是不行了
/*
class zncommon extends zn;
class znwarn extends zn;
class zndanger extends zn;

class emailcomm extends email;
class emailwarn extends email;
class emaildanger extends email;
....
*/

/**
 * 思考:
 * 信的发送方式是一个变化因素
 * 信的紧急程度是一个变化因素,
 * 为了不修改父类, 只好考虑2个因素的组织, 不停产生新类....
 */
abstract class info {
    protected $send = null;

    public function __construct($send) {
        $this->send = $send;
    }

    abstract public function msg($content);
    public function send($to, $content){
        $content = $this->msg($content);
        $this->send->send($to, $content);
    }
}

class zn {
    public function send($to, $content) {
        echo '站内给: ', $to, '内容是: ', $content;
    }
}

class email {
    public function send($to, $content) {
        echo 'email给: ', $to, '内容是: ', $content;
    }
}

class sms {
    public function send($to, $content) {
        echo 'sms给: ', $to, '内容是: ', $content;
    }
}

class commoninfo extends info{
    public function msg($content) {
        return '普通'. $content;
    }
}

class warninfo  extends info{
    public function msg($content) {
        return '紧急'.$content;
    }
}

class dangerinfo  extends info{
    public function msg($content) {
        return '紧急'.$content;
    }
}

// 用站内发普通信息
$commoninfo = new commoninfo(new zn());
$commoninfo->send('小明', '吃饭了');

//给小刚发紧急手机短信消息
$dangerinfo = new dangerinfo(new sms());
$dangerinfo->send('小刚', '失火了');

// 本来需要3x3个类
// 现在只需要3+3个类了
// 现在耦合了, view中不写逻辑, 数据库三范式, 老有相同的字段, 为了速度, 之前的设计模式都是在解耦, 现在反而增加了耦合, 是为了防止子类爆炸

以上就介绍了PHP常用设计模式单例, 工厂, 观察者, 责任链, 装饰, 策略,适配,桥接模式,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

人气教程排行