• PHP之常用设计模式


      在日常开放中,经常会用到一些设计模式,进行我们代码的优化处理,一个很好的设计思想

    1) 工厂模式

      在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象

    /**
     * 定义数据库接口
     */
    interface DB {
        // 连接数据库
        public function conn();
    }
    
    /**
     * 工厂接口
     */
    interface Factory{
        // 创建数据库接口
        function createDB();
    }
    
    /**
     * 实现DB接口的mysql类
     */
    class mysqlDB implements DB{
        public function conn(){
            echo '连接到mysql数据库';
        }
    }
    
    /**
     * 实现DB接口的sqlite类
     */
    class sqLiteDB implements DB{
        public function conn(){
            echo '连接到了sqlite数据库';
        }
    }
    
    /**
     * 创建对应的数据库对象工厂类
     */
    class mysqlFactory implements Factory{
        public function createDB(){
            return new mysqlDB();
        }
    }
    
    /**
     * 创建对应的数据库对象工厂类
     */
    class sqliteFactory implements Factory{
        public function createDB(){
            return new sqLiteDB();
        }
    }
    
    ////////////////////
    // 假设新增MongoDB数据库 //
    ////////////////////
    
    // 1:要新增mongoDB()
    /**
     * 实现DB接口的mongo类
     */
    class mongoDB implements DB{
        public function conn(){
            echo '连接到了mongodb数据库';
        }
    }
    // 2:新增对应的工厂方法
    class mongoFactory implements Factory{
        public function createDB(){
            return new mongoDB();
        }
    }
    
    
    // 测试
    $mysqlfactory=new mysqlFactory();
    $mysqldb=$mysqlfactory->createDB();
    $mysqldb->conn();
    
    $sqlitefactory=new sqliteFactory();
    $sqlitedb=$sqlitefactory->createDB();
    $sqlitedb->conn();
    
    $mongofactory=new mongoFactory();
    $mongodb=$mongofactory->createDB();
    $mongodb->conn();

    这样就不违反了开闭规则了,不修改已有的代码,直接添加新的代码,提高了程序的扩展性。

    2)单例模式

      可以保证系统中一个类只有一个实例。即一个类只有一个对象实例

    class sigle{
        // 保存唯一对象
        private static $selfObj=null;
        // 目的:封锁外部new操作
        private function __construct(){}
        // 封锁外部clone
        private function __clone(){}
    
        public static function getObj(){
            if(self::$selfObj===null){
                self::$selfObj=new self();
            }
            return self::$selfObj;
        }
    }
    
    $q=sigle::getObj();
    $w=sigle::getObj();
    var_dump($q==$w);

    3)观察者模式

    // php5中提供SplObserver与被观察者SplSubject的接口
    
    ///////////////////////////////
    // 定义被观察者,实现SplSubject被观察者对象 //
    ///////////////////////////////
    class User implements SplSubject{
        // 登陆次数
        public $loginNum;
        // 用户爱好
        public $hobby;
        // 用户名字
        public $name;
    
        public function __construct($name,$hobby=''){
            $this->loginNum=rand(1,10);
            $this->hobby=$hobby;
            $this->name=$name;
            // 用来保存观察者的对象
            $this->observers=new SplObjectStorage();
        }
    
        // 用户登录入口
        public function login(){
            echo '登录成功后通知:';
            $this->notify();
        }
    
        // 添加观察者
        public function attach(SplObserver $observer){
            $this->observers->attach($observer);
        }
    
        // 删除观察者
        public function detach(SplObserver $observer){
            $this->observers->detach($observer);
        }
    
        /**
         * 循环遍历观察者发送通知
         */
        public function notify(){
            // 指针指向头部
            $this->observers->rewind();
            while ($this->observers->valid()) {
                // 当前观察者
                $observer=$this->observers->current();
                // var_dump($observer);
                // 传递当前用户
                $observer->update($this);
                $this->observers->next();
            }
        }
    }
    
    ///////////////
    // 定义安全验证观察者 //
    ///////////////
    class Secrity implements SplObserver{
        /**
         * 本观察者通知的具体方法
         * @param  SplSubject $subject [被观察者user]
         */
        public function update(SplSubject $subject){
            if($subject->loginNum<=3){
                echo $subject->name.',这是第'.$subject->loginNum.'登录.';
            }else{
                echo $subject->name.',这是第'.$subject->loginNum.'登录,登录次数过多.';
            }
        }
    }
    
    ///////////////
    // 定义广告推荐观察者 //
    ///////////////
    class Commend implements SplObserver{
        public function update(SplSubject $subject){
            if($subject->hobby=='car'){
                echo '给你推荐汽车广告'.PHP_EOL;
            }else if($subject->hobby=='php'){
                echo '推荐php培训广告'.PHP_EOL;
            }else{
                echo '好好学习,天天向上'.PHP_EOL;
            }
        }
    }
    
    // 测试
    $ming=new User('小明','php');
    // 添加观察者
    $secrity=new Secrity();
    $ming->attach($secrity);
    $commend=new Commend();
    $ming->attach($commend);
    $ming->login();
    
    echo '------------------------------------------------------'.PHP_EOL;
    
    $hong=new User('小红');
    // 添加观察者
    $secrity=new Secrity();
    $hong->attach($secrity);
    $commend=new Commend();
    $hong->attach($commend);
    // 删除广告推荐
    $hong->detach($commend);
    $hong->login();

    4)责任链模式

    // 领班
    class Foreman{
        // 自己的等级
        private $level=1;
        // 上级
        protected $superior='Director';
        public function process($level){
            if($this->level>=$level){
                // 自己能处理问题的级别大于等于当前事情级别,就自己处理
                echo '领班处理'.PHP_EOL;
            }else{
                (new $this->superior)->process($level);
            }
        }
    }
    
    // 主管
    class Director{
        // 自己的等级
        private $level=2;
        // 上级
        protected $superior='Manager';
        public function process($level){
            if($this->level>=$level){
                echo '主管处理'.PHP_EOL;
            }else{
                (new $this->superior)->process($level);
            }
        }
    }
    
    // 经理
    class Manager{
        // 自己的等级
        private $level=3;
        // 上级
        protected $superior='TopManager';
        public function process($level){
            if($this->level>=$level){
                echo '经理处理'.PHP_EOL;
            }else{
                (new $this->superior)->process($level);
            }
        }
    }
    
    // 总经理
    class TopManager{
        // 自己的等级
        private $level=4;
        // 上级
        protected $superior='President';
        public function process($level){
            if($this->level>=$level){
                echo '总经理处理'.PHP_EOL;
            }else{
                (new $this->superior)->process($level);
            }
        }
    }
    
    // 董事长
    class President{
        // 自己的等级
        private $level=5;
        public function process($level){
            echo '董事长处理'.PHP_EOL;
        }
    }
    
    // 责任链模式处理问题
    $level=rand(1,5);
    print('问题级别:'.$level);
    $foreman=new Foreman();
    $foreman->process($level);

    5)策略模式

    // 计算的接口
    interface Calc{
        public function process($num1,$num2);
    }
    
    // 加法计算
    class AddCalc implements Calc{
        public function process($num1,$num2){
            return $num1+$num2;
        }
    }
    
    // 减法计算
    class SubtractCalc implements Calc{
        public function process($num1,$num2){
            return $num1-$num2;
        }
    }
    
    // 乘法计算
    class MultiplyCalc implements Calc{
        public function process($num1,$num2){
            return $num1*$num2;
        }
    }
    
    // 除法计算
    class DivideCalc implements Calc{
        public function process($num1,$num2){
            return $num1/$num2;
        }
    }
    
    // 计算器类
    class Calculator{
        // 保存计算类
        private $calc=null;
        /**
         * @param [string] $operator [计算器运算方法]
         */
        public function __construct($operator){
            $operCalc=$operator.'Calc';
            $this->calc=new $operCalc();
        }
    
        // 计算
        public function calc($num1,$num2){
            return $this->calc->process($num1,$num2);
        }
    }
    
    $operators=array('Add','Subtract','Divide','Multiply');
    $oper=$operators[rand(0,3)];
    $calculator=new Calculator($oper);
    $res=$calculator->calc(100,2);
    echo '100 '.$oper.' 2 res:'.$res;

    6)装饰器模式

    // 装饰器模式做文章修饰功能
    
    // 基本的文章类
    class BaseArticle{
        // 文章内容
        protected $text;
        // 文章对象
        protected $artObj=null;
    
        public function __construct($text){
            $this->text=$text;
        }
        public function decorator(){
            return $this->text;
        }
    }
    
    // 添加文章摘要,继承基础文章
    class SummaryArticle extends BaseArticle{
        // 传递一个文章对象
        public function __construct(BaseArticle $artObj){
            $this->artObj=$artObj;
            $this->decorator();
        }
    
        public function decorator(){
            return $this->text='【加了摘要】'.$this->artObj->text;
        }
    }
    
    // 添加文章写作时间,继承基础文章
    class TimeArticle extends BaseArticle{
        public function __construct(BaseArticle $artObj){
            $this->artObj=$artObj;
            $this->decorator();
        }
    
        public function decorator(){
            return $this->text=$this->artObj->text.'【时间:'.date('Y-m-d H:i:s').'';
        }
    }
    
    $ba=new BaseArticle('文章主体-文章主体-文章主体-文章主体。');
    $sa=new SummaryArticle($ba);
    $ta=new TimeArticle($sa);
    echo $ba->decorator().PHP_EOL;
    echo $sa->decorator().PHP_EOL;
    echo $ta->decorator().PHP_EOL;

    7)适配器模式

    // 假设天气接口
    class Weather{
        public static function show(){
            $today=array(
                "city"=>"北京",
                "cityid"=>"101010100",
                "temp1"=>"24℃",
                "temp2"=>"11℃",
                "weather"=>"雷阵雨转多云"
            );
            // 将数据序列化,只能是php才能反序列化操作
            /*a:5:{s:4:"city";s:6:"北京";s:6:"cityid";s:9:"101010100";s:5:"temp1";s:5:"24℃";s:5:"temp2";s:5:"11℃";s:7:"weather";s:18:"雷阵雨转多云";}城市:北京*/
            return serialize($today);
        }
    }
    
    /**
     * 适配器将php序列化后的数据反序列化后转化成json格式,这样其他语言就能处理了
     */
    class AdapterWeather extends Weather{
        public static function show(){
            return json_encode(unserialize(parent::show()));
        }
    }
    
    // php客户端调用
    print(Weather::show());
    $weather=unserialize(Weather::show());
    echo '城市:'.$weather['city'].PHP_EOL;
    echo '城市ID:'.$weather['city'].PHP_EOL;
    echo '最高温:'.$weather['temp1'].PHP_EOL;
    echo '最低温:'.$weather['temp2'].PHP_EOL;
    echo '天气:'.$weather['weather'].PHP_EOL;
    
    echo '--------------以下假设是python通过适配器获取天气数据----------'.PHP_EOL;
    // 假设python处理天气,通过适配器获取天气数据
    $weather=json_decode(AdapterWeather::show(),true);
    echo '城市:'.$weather['city'].PHP_EOL;
    echo '城市ID:'.$weather['city'].PHP_EOL;
    echo '最高温:'.$weather['temp1'].PHP_EOL;
    echo '最低温:'.$weather['temp2'].PHP_EOL;
    echo '天气:'.$weather['weather'].PHP_EOL;

    8)桥接模式

    // 抽象消息接口
    abstract class Message{
        // 发送器
        protected $sender;
        public function __construct($sender){
            $this->sender=$sender;
        }
        // 发送消息
        public function send($to,$msg){
            $msg=$this->msg($msg);
            // 通过发送器发送消息
            $this->sender->send($to,$msg);
        }
    }
    
    // 普通消息类型
    class NormalMessage extends Message{
        public function msg($msg){
            return '【普通】'.$msg;
        }
    }
    
    // 警告消息类型
    class WarningMessage extends Message{
        public function msg($msg){
            return '【警告】'.$msg;
        }
    }
    
    // 危险消息类型
    class DangerMessage extends Message{
        public function msg($msg){
            return '【危险】'.$msg;
        }
    }
    
    
    // 发送站内消息发送器
    class SiteMessageSender{
        public function send($to,$msg){
            echo '给"'.$to.'"发送站内消息: '.$msg.PHP_EOL;
        }
    }
    
    
    // 发送email消息发送器
    class EmailMessageSender{
        public function send($to,$msg){
            echo '给"'.$to.'"发送Email消息: '.$msg.PHP_EOL;
        }
    }
    
    // 发送短信消息发送器
    class SMSMessageSender{
        public function send($to,$msg){
            echo '给"'.$to.'"发送短信消息: '.$msg.PHP_EOL;
        }
    }
    
    // 总共有9种组合方式,但是仅仅需要6个类
    
    $normal_msg=new NormalMessage(new SiteMessageSender());
    $normal_msg->send('小红','normal信息信息信息');
    $normal_msg=new NormalMessage(new EmailMessageSender());
    $normal_msg->send('小红','normal信息信息信息');
    $normal_msg=new NormalMessage(new SMSMessageSender());
    $normal_msg->send('小红','normal信息信息信息');
    
    $warning_msg=new WarningMessage(new SiteMessageSender());
    $warning_msg->send('小绿','warning信息信息信息');
    $warning_msg=new WarningMessage(new EmailMessageSender());
    $warning_msg->send('小绿','warning信息信息信息');
    $warning_msg=new WarningMessage(new SMSMessageSender());
    $warning_msg->send('小绿','warning信息信息信息');
    
    $danger_msg=new DangerMessage(new SiteMessageSender());
    $danger_msg->send('小花','danger信息信息信息');
    $danger_msg=new DangerMessage(new EmailMessageSender());
    $danger_msg->send('小花','danger信息信息信息');
    $danger_msg=new DangerMessage(new SMSMessageSender());
    $danger_msg->send('小花','danger信息信息信息');
  • 相关阅读:
    2018山东省赛补题
    USACO 2006 November Gold Corn Fields /// 状压 oj23941
    East Central North America 2006 Hie with the Pie /// 状压dp oj22470
    USACO 2003 Fall Orange Cow Exhibition /// 负数01背包 oj22829
    UASCO Cow Pedigrees /// oj10140
    滑雪 矩阵中的最长上升路径 /// 记忆化DFS || DP oj22919
    十四届华中科大赛补题
    USACO 2007 February Silver The Cow Lexicon /// DP oj24258
    POJ 3252 区间内一个数的二进制中0的数量要不能少于1的数量(数位DP)
    HDU 4734 F(x) (数位DP)
  • 原文地址:https://www.cnblogs.com/xingxia/p/php_modes.html
Copyright © 2020-2023  润新知