• 七. PHP模式设计----运行及描写叙述任务


    1. 解析器模式
    
    
    //解析器内容类
    //用于存放表达式的运算结果,并且能依据传入的表达式返回当初记录的结果
    class InterpreterContext{
        private $expressionstore=array();
        //将对象放进array里面,索引號是对象ID号
        function replace(Expression $exp,$value){
            $this->expressionstore[$exp->getKey()]=$value;
        }
        function lookup(Expression $exp){
            return $this->expressionstore[$exp->getKey()];
        }
    }
    abstract class Expression{
        private static $keyCount=0;
        private $key;
        abstract function interpret(InterpreterContext $context);
        //每个对象都有一个唯一的key
        function getKey(){
            if(!isset($this->key)){
                $this->key=++self::$keyCount;
            }
            return $this->key;
        }
    }
    //字符串
    class LiteralExpression extends Expression{
        private $value;
        function __construct($value){
            $this->value=$value;
        }
        function interpret(InterpreterContext $context){
            $context->replace($this, $this->value);
        }
    }
    //变量
    class VariableExpression extends Expression{
        private $value;
        private $name;
        function __construct($name,$value=null){
            $this->name=$name;
            $this->value=$value;
        }
        function setValue($value){
            $this->value=$value;
        }
        function getKey(){
            return $this->name;
        }
        function interpret(InterpreterContext $context){
            if(!is_null($this->value)){
                $context->replace($this, $this->value);
                //设置为空,能够避免在没有修改value的情况下再次调用该方法的时候,
                //也第二次调用了InterpreterContext::replece
                $this->value=null;
            }
        }
    }
    //操作符表达式 抽象基类
    abstract class OperatorExpression extends Expression{
        //左右操作数
        protected $l_op;
        protected $r_op;
        function __construct(Expression $l_op,Expression $r_op){
            $this->l_op=$l_op;
            $this->r_op=$r_op;
        }
        function interpret(InterpreterContext $context){
            $this->l_op->interpret($context);
            $this->r_op->interpret($context);
            $result_l=$context->lookup($this->l_op);
            $result_r=$context->lookup($this->r_op);
            $this->doInterpret($context, $result_l, $result_r);
        }
        protected abstract function doInterpret(InterpreterContext $context,$result_l,$result_r);
    }
    //相等表达式
    class EqualsExpression extends OperatorExpression{
        //计算后将结果保存进this里...
        protected function doInterpret(InterpreterContext $context,$result_l,$result_r){
            $context->replace($this, $result_l==$result_r);
        }
    }
    //布尔或表达式
    class BooleanOrExpression extends OperatorExpression{
        protected function doInterpret(InterpreterContext $context, $result_l, $result_r){
            $context->replace($this, $result_l || $result_r);
        }
    }
    //布尔与表达式
    class BooleanAndExpression extends OperatorExpression{
        protected function doInterpret(InterpreterContext $context, $result_l, $result_r){
            $context->replace($this, $result_l && $result_r);
        }
    }
    /*
    $context=new InterpreterContext();
    $literal=new LiteralExpression("Bob");
    $literal->interpret($context);
    print $context->lookup($literal);//Bob
    $context=new InterpreterContext();
    $myvar=new VariableExpression("V","one");
    $myvar->interpret($context);
    print $context->lookup($myvar);//one
    $myothervar=new VariableExpression("V");
    $myvar->interpret($context);
    print $context->lookup($myvar);//one
    */
    //利用上面的代码来检測迷你型语言
    //$input equals "4" or $input equals "four"
    $context=new InterpreterContext();
    //一个没有赋值的变量
    $input=new VariableExpression('input');
    //定义一个复杂的布尔型变量,初始化的參数被保存在l_op,r_op里面
    //注意,此时他们还没有进行相关运算,必须等到调用布尔型变量的interpret()
    //之后,布尔型变量里面的參数才会各自调用自身的interpret,形成一个调用栈...
    $statement=new BooleanOrExpression(
            new EqualsExpression($input, new LiteralExpression('four')), 
            new EqualsExpression($input, new LiteralExpression('4')));
    $statement->interpret($context);
    print $context->lookup($statement);
    foreach (array('four','4','52') as $val){
        $input->setValue($val);
        print "$val:
    ";
        $statement->interpret($context);
        if($context->lookup($statement)){
            print "top marks
    ";
        }else{
            print "dunce hat on
    
    ";
        }
    }
    /*four:
    top marks
    4:
    top marks
    52:
    dunce hat on*/  
    
    2.策略模式
          将类中很多不同操作并且是来自同一个接口的算法,独立起来封装在一个新类中,主类在由分类组合或者聚合而成
    
    //Question类将由Marker聚合而成
    abstract class Question{
        protected $prompt;
        protected $marker;
        function __construct($prompt,Marker $marker){
            $this->marker=$marker;
            $this->prompt=$prompt;
        }
        //利用托付实现
        function mark($response){
            return $this->marker->mark($response);
        }
    }
    class TextQuestion extends Question{
        //处理文本问题特有的操作
    }
    class AVQuestion extends Question{
        //处理语音问题特有操作
    }
    //策略对象
    //将算法部分独立出来封装在Marker类中....
    abstract class Marker{
        protected $test;
        function __construct($test){
            $this->test=$test;
        }
        abstract function mark($response);
    }
    //MarkLogic语言
    class MarkLogicMarker extends Marker{
        protected $engine;
        function __construct($test){
            parent::__construct($test);
        }
        function mark($response){
            //模拟返回true
            return true;
        }
    }
    //直接匹配
    class MatchMarker extends Marker{
        function mark($response){
            return ($this->test==$response);
        }
    }
    //正則表達式
    class RegexpMarker extends Marker{
        function mark($response){
            return (preg_match($this->test, $response));
        }
    }
    //client演示样例代码
    $markers=array(new RegexpMarker("/f.ve/"),
            new MatchMarker("fivev"),
            new MarkLogicMarker('$input equals "five"'));
    foreach($markers as $marker){
        print get_class($marker)."
    ";
        //新建一个问题,将marker实例传进去
        $question=new TextQuestion("How many beans make five", $marker);
        foreach (array("five","four") as $response){
            print "	 response:$response: ";
            if($question->mark($response)){
                print "well done
    ";
            }else{
                print "never mind
    ";
            }
        }
    }
    /*RegexpMarker
         response:five: well done
         response:four: never mind
    MatchMarker
         response:five: never mind
         response:four: never mind
    MarkLogicMarker
         response:five: well done
         response:four: well done
    */
    
    3 观察者模式
    
         观察者模式的和兴是把客户元素(观察者)从一个中心类中分离开来.当主体中有事件发生时,观察者必须被通知到!同一时候观察者和主体类不是通过硬编码实现,而是通过接口组合聚合实现
    *问题
    // Login类(主体类)
    class Login {
        const LOGIN_USER_UNKNOWN = 1;
        const LOGIN_WRONG_PASS = 2;
        const LOGIN_ACCESS = 3;
        private $status = array ();
        // 登录操
        function handleLogin($user, $pass, $ip) {
            $ret=false;
            switch (rand ( 1, 3 )) {
                case 1 :
                    $this->setStatus ( self::LOGIN_ACCESS, $user, $ip );
                    $ret=ture;
                    break;
                case 2 :
                    $this->setStatus ( self::LOGIN_WRONG_PASS, $user, $ip );
                    $ret=false;
                    break;
                case 3 :
                    $this->setStatus ( self::LOGIN_USER_UNKNOWN, $user, $ip );
                    $ret=false;
                    break;
                default:
                    $ret=false;
            }
            //假设须要记录IP时
            Logger::logIP($user, $ip, $this->getStatus());
            //假设须要把登录失败的人的IP发送到管理员邮箱时...
            if(!$ret){
                Notifier::mailWarning($user, $ip, $this->getStatus());
            }
            //还须要其它功能时,比方特殊IP须要设置cookie等...
            //须要在这里面一直加入...
            return $ret;
        }
        function setStatus($status, $user, $ip) {
            $this->status = array ($status,$user,$ip);
        }
        function getStatus(){
            return $this->status;
        }
    }
    class Logger{
        static function logIP($user,$ip,$status){}
    }
    class Notifier{
        static function mailWarning($user,$ip,$status){}
    }
    *利用观察者模式,使代码修改少些....
    // 主体类的抽象接口
    interface Observable{
        //附加
        function attach(Observer $observer);
        //删除
        function detach(Observer $observer);
        //通知
        function notify();
    }
    // Login类(主体类)
    class Login implements Observable{
        const LOGIN_USER_UNKNOWN = 1;
        const LOGIN_WRONG_PASS = 2;
        const LOGIN_ACCESS = 3;
        private $observers;
        private $status = array ();
        // 登录操作
        function handleLogin($user, $pass, $ip) {
            $ret=false;
            switch (rand ( 1, 3 )) {
                case 1 :
                    $this->setStatus ( self::LOGIN_ACCESS, $user, $ip );
                    $ret=ture;
                    break;
                case 2 :
                    $this->setStatus ( self::LOGIN_WRONG_PASS, $user, $ip );
                    $ret=false;
                    break;
                case 3 :
                    $this->setStatus ( self::LOGIN_USER_UNKNOWN, $user, $ip );
                    $ret=false;
                    break;
                default:
                    $ret=false;
            }
            //使用观察者模式之后,假设须要添加新功能,仅仅须要在本类中加入观察者实例就可以...
            $this->notify();
            return $ret;
        }
        function setStatus($status, $user, $ip) {
            $this->status = array ($status,$user,$ip);
        }
        function getStatus(){
            return $this->status;
        }
        function attach(Observer $observer){
            $this->observers[]=$observer;
        }
        function detach(Observer $observer){
            $newObserver=array();
            foreach ($this->observers as $obs){
                if($obs!==$observer){
                    $newObserver[]=$obs;
                }
            }
            $this->observers=$newObserver;
        }
        //通知全部观察者
        function notify(){
            foreach ($this->observers as $bos){
                $bos->update($this);
            }
        }
    }
    //观察者接口
    interface Observer{
        function update(Observable $observable);
    }
    class SecurityMonitor implements Observer{
        function update(Observable $observable){
            //getStatus()不是Observable接口规定的方法
            $status=$observable->getStatus();
            //对status的推断也涉及到耦合问题
            if($status[0]==Login::LOGIN_WRONG_PASS){
                //发送邮件给管理员
                print __CLASS__.":	 sending mail to sysadmin
    ";
            }
        }
    }
    $login=new Login();
    $login->attach(new SecurityMonitor());
    $login->handleLogin("coco", "123456", "127.0.0.1");//有可能输出发送消息到管理员
    
     *改进后的观察者模式
    
    //可观察元素:主体类的基接口
    interface Observable{
        //附加
        function attach(Observer $observer);
        //删除
        function detach(Observer $observer);
        //通知
        function notify();
    }
    // Login类(主体类)
    class Login implements Observable{
        const LOGIN_USER_UNKNOWN = 1;
        const LOGIN_WRONG_PASS = 2;
        const LOGIN_ACCESS = 3;
        private $observers;
        private $status = array ();
        // 登录操作
        function handleLogin($user, $pass, $ip) {
            $ret=false;
            switch (rand ( 1, 3 )) {
                case 1 :
                    $this->setStatus ( self::LOGIN_ACCESS, $user, $ip );
                    $ret=ture;
                    break;
                case 2 :
                    $this->setStatus ( self::LOGIN_WRONG_PASS, $user, $ip );
                    $ret=false;
                    break;
                case 3 :
                    $this->setStatus ( self::LOGIN_USER_UNKNOWN, $user, $ip );
                    $ret=false;
                    break;
                default:
                    $ret=false;
            }
            //使用观察者模式之后,假设须要添加新功能,仅仅须要在本类中加入观察者实例就可以...
            $this->notify();
            return $ret;
        }
        function setStatus($status, $user, $ip) {
            $this->status = array ($status,$user,$ip);
        }
        function getStatus(){
            return $this->status;
        }
        function attach(Observer $observer){
            $this->observers[]=$observer;
        }
        function detach(Observer $observer){
            $newObserver=array();
            foreach ($this->observers as $obs){
                if($obs!==$observer){
                    $newObserver[]=$obs;
                }
            }
            $this->observers=$newObserver;
        }
        //通知全部观察者
        function notify(){
            foreach ($this->observers as $bos){
                $bos->update($this);
            }
        }
    }
    //观察者接口
    interface Observer{
        function update(Observable $observable);
    }
    //Login:观察者超类(用于解决直接在Observer中调用详细的Observable子类造成的风险)
    abstract class LoginObserver implements Observer{
        private $login;
        function __construct(Login $login){
            $this->login=$login;
            $this->login->attach($this);
        }
        //该方法在Observable的子类某些方法被调用时触发
        function update(Observable $observable){
            //触发该方法时,传入的參数必须是Login才有效...
            if($this->login===$observable){
                 $this->doUpdate($observable);
            }
        }
        abstract function doUpdate(Login $login);
        
    }
    //改进后的观察者能保证调用的Observable实例方法一定存在
    class SecurityMonitor extends LoginObserver{
        function doUpdate(Login $login){
            $status=$login->getStatus();
            //对status的推断也涉及到耦合问题
            if($status[0]==Login::LOGIN_WRONG_PASS){
                //发送邮件给管理员
                print __CLASS__.":	 sending mail to sysadmin
    ";
            }
        }
    }
    //日常记录
    class GeneralLogger extends LoginObserver{
        function doUpdate(Login $login){
            $status=$login->getStatus();
            //加入记录到log中
            //...
            print __CLASS__."	 add login data to log
    ";
        }
    }
    //合作伙伴工具类
    class PartnershipTool extends LoginObserver{
        function doUpdate(Login $login){
            $status=$login->getStatus();
            //检查IP,假设匹配,则设置cookie...
            //...
            print __CLASS__."	 set cookie if IP matches a list
    ";
        }
    }
    //client代码有一点点改变...
    $login=new Login();
    new SecurityMonitor($login);
    new GeneralLogger($login);
    new PartnershipTool($login);
    $login->handleLogin("coco", "123456", "127.0.0.1");
    /*
     * 有可能输出
     *SecurityMonitor:     sending mail to sysadmin
     *GeneralLogger     add login data to log
     *PartnershipTool    set cookie if IP matches a list
     **/
    
    4. 訪问者模式
           当使用对象集合时,我们可能须要对结构上每个单独的组件应用各种操作.这种操作能够内建于组件本身,毕竟组件内部调用其它组件是最方便的. 
           可是这个方案也存在问题,由于我们并不知道全部可能须要的运行的操作.假设每添加一个操作,就在类中添加一个对于新操作的支持,类就会变得越来越臃肿.訪问者模式能够解决问题.
    
    //本例是基于"文明"游戏的代码建立而成...
    //*战斗单元类
    abstract class Unit{
        //深度
        protected $depth=0;
        //攻击强度
        abstract function bombardStrength();
        function getComposite(){
            return null;
        }
        //为訪问者模式打造的方法
        function accept(ArmyVisitor $visitor){
            //构建一个依据自己规则定义的方法名,然后交给visitor自身调用
            $method="visit".get_class($this);
            $visitor->$method($this);
        }
        //用于计算Unit在对象树中的深度
        protected function setDepth($depth){
            $this->depth==$depth;
        }
        function getDepth(){
            return $this->depth;
        }
    }
    //复合抽象类
    abstract class CompositeUnit extends Unit{
        protected $units=array();
        //为訪问者模式打造的方法
        function accept(ArmyVisitor $visitor){
            //构建一个依据自己规则定义的方法名,然后交给visitor自身调用
            //先调用父类accept(),再遍历调用子元素accept()
            parent::accept($visitor);
            foreach ($this->units as $thisunit){
                $thisunit->accept($visitor);
            }
        }
        //能够不用写bombardStrength()
        function getComposite(){
            return $this;
        }
        //加入单元
        //同一时候标记节点在对象树中的深度
        function addUnit(Unit $unit){
            if(!empty($unit)){
                if(in_array($unit, $this->units,true)){
                    return;
                }
                //能够用以下代码替换in_array()函数
    //             foreach ($this->units as $thisunit){
    //                 if($thisunit===$unit){
    //                     return;
    //                 }
    //             }
                //计算好深度先...
                $unit->setDepth($this->depth+1);
                array_push($this->units, $unit);
            }
        }
        function removeUnit(Unit $unit){
            $this->units=array_udiff($this->units, array($unit), function ($a,$b){return ($a===$b?0:1);});
        }
        
    }
    //射手
    class Archer extends Unit{
        function bombardStrength(){
            return 4;
        }
    }
    //激光塔
    class LaserCannonUnit extends Unit{
        function bombardStrength(){
            return 44;
        }
    }
    //军队:由战斗单元组成
    class Army extends CompositeUnit{
        //计算总强度
        function bombardStrength(){
            $ret=0;
            foreach ($this->units as $unit){
                $ret+=$unit->bombardStrength();
            }
            return $ret;
        }
        //移动能力,防御能力...省略
    }
    //运兵船:一个相似军队的单元,它具备10个战斗单元,有攻击力
    class TroopCarrier extends CompositeUnit{
        //具备和军队差点儿相同的方法和属性
        function bombardStrength(){
            //Do something...
        }
    }
    //军队訪问者基类
    abstract class ArmyVisitor{
        //相关方法待会写...
        //Army可能有多少种Unit,这里就有多少个visit方法...
        //方法命名规则为visit+类名
        //默认的visit
        abstract function visit(Unit $unit);
        function visitArcher(Archer $node){
            $this->visit($node);
        }
        function visitLaserCannonUnit(LaserCannonUnit $node){
            $this->visit($node);
        }
        function visitArmy(Army $node){
            $this->visit($node);
        }
        function visitTroopCarrier(TroopCarrier $node){
            $this->visit($node);
        }
    }
    //详细的Army訪问者类,用于转存文本
    class TextDumpArmyVisitor extends ArmyVisitor{
        private $text="";
        function visit(Unit $node){
            $ret="";
            $pad=4*$node->getDepth();
            $ret.=sprintf("%{$pad}s","");
            $ret.=get_class($node).":";
            $ret.="bombard: ".$node->bombardStrength()."
    ";
            $this->text.=$ret;
        }
        function getText(){
            return $this->text;
        }
    }
    //client实例代码
    $army=new Army();
    $army->addUnit(new Archer());
    $army->addUnit(new LaserCannonUnit());
    $textdump=new TextDumpArmyVisitor();
    $army->accept($textdump);
    print $textdump->getText();
    /*  
     *  Army:bombard: 48
     *  Archer:bombard: 4
     *  LaserCannonUnit:bombard: 44
     */
    
    5. 命令模式
    //命令模式
    //命令模式最初来源于图形化用户界面设计,但如今广泛应用于企业应用设计,特别促进了控制器(请求和分法处理)
    //和领域模型(应用逻辑)的分离.说得更简单一点,命令模式有助于系统更好地进行组织,并易于扩展
    //Command能够设计成接口,由于它非常easy...
    //Commands/Command.php
    abstract class Command{
        abstract function execute(CommandContext $context);
    }  
    require_once("Command.php");
    class Registry{
        //一个空类...
        static function getAccessManager(){
            return new AccessManager();
        }
    }
    class AccessManager{
        function login(){
            return new stdClass();
        }
        function getError(){}
    }
    class LoginCommand extends Command{
        function execute(CommandContext $context){
            $manager=Registry::getAccessManager();
            $user=$context->get('username');
            $user=$context->get('pass');
            //虚构出来的空类空方法
            $user_obj=$manager->login();
            if(is_null($user_obj)){
                $context->setError($manager->getError());
                return false;
            }
            $context->addParam("user", $user);
            return true;
        }
    }  
    //CommandContext类用来做任务扩增用,在这儿主要功能是传递数据给Command类
    class CommandContext{
        private $params=array();
        private $error="";
        function __construct(){
            $this->params=$_REQUEST;
        }
        function addParam($key,$val){
            $this->params[$key]=$val;
        }
        function get($key){
            return $this->params[$key];
        }
        function setError($error){
            $this->error=$error;
        }
        function getError(){
            return $this->error;
        }
    }
    //client代码(用于创建命令)已经调用者代码
    class CommandNotFoundException extends Exception{
        
    }
    //创建命令的工厂
    class CommandFactory{
        private static $dir="Commands";
        //依据參数action,以及类文件存放文件夹$dir动态创建对应的$action+Command类
        static function getCommand($action='default'){
            //匹配是否出现非法字符(非字母数字下划线)
            if(preg_match('/W/', $action)){
                throw new Exception("Illegal characters in action");
            }
            $class=ucfirst(strtolower($action)."Command");
            $file=self::$dir.DIRECTORY_SEPARATOR."{$class}.php";
            if(!file_exists($file)){
                throw new CommandNotFoundException("File could not be find !");
            }
            require_once("$file");
            if(!class_exists($class)){
                throw new CommandNotFoundException("Class could not be find !");
            }
            return new $class();
        }
    }
    //调用者,里面包括一个CommandContext对象实例,用于存放web请求的数据
    class Controller{
        private $context;
        function __construct(){
            $this->context=new CommandContext();
        }
        function getContext(){
            return $this->context;
        }
        function process(){
            $cmd=CommandFactory::getCommand($this->getContext()->get('action'));
            if(!$cmd->execute($this->context)){
                //处理失败
                print "Faile in process!";
            }else{
                //处理成功,能够显示对应的视图层
                print "Success in process!";
            }
        }
    }
    $controller=new Controller();
    $context=$controller->getContext();
    $context->addParam('action', 'Login');
    $context->addParam('user', 'cocos');
    $context->addParam('pass', 'tiddles');
    //controller运行process方法,须要不理解command的意义.
    $controller->process();//Success in process
    
    
    
    
    
    
    
    
    
    


  • 相关阅读:
    WSL下的Ubuntu 18.04LTS配置软件源和系统更新
    宝塔 5.9.2 最终版 专业版
    宝塔面板7.2.0学习版集合--包含(专业版、企业版及部分插件)
    网络安全学习和CTF必不可少的一些网站
    Hello Blog !
    如何解决机器学习树集成模型的解释性问题
    机器学习建模老司机的几点思考与总结
    2019 秋招提前批蘑菇街一面面经(带答案)
    Java 最全异常讲解
    Spring Context 你真的懂了吗
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/7258179.html
Copyright © 2020-2023  润新知