轻松掌握php设计模式之访问者模式


Posted in PHP onSeptember 23, 2016

访问者模式解决的问题

在我们的代码编写过程当中,经常需要对一些类似的对象添加一些的代码,我们以一个计算机对象打印组成部分为例来看下:

/**
  * 抽象基类
  */
  abstract class Unit
  {
    /**
    *获取名称
    */
    abstract public function getName();

  }

  /**
  * Cpu类
  */
  class Cpu extends Unit
  {
    public function getName()
    {
      return 'i am cpu';
    }
  }

  /**
  * 内存类
  */
  class Memory extends Unit
  {
    public function getName()
    {
      return 'i am memory';
    }
  }

  /**
  * 键盘类
  */
  class Keyboard extends Unit
  {
    public function getName()
    {
      return 'i am keyboard';
    }
  }

  /**
  * 计算机类
  */
  class Computer
  {
    protected $_items = [];

    public function add(Unit $unit)
    {
      $this->_items[] = $unit;
    }

    public function print()
    {
      // 循环打印各个组成部分
      foreach ($this->_items as $item) {
        $item->getName();
      }
    }
  }

这个时候上面的代码看上去好像很完美的样子,但是问题来了,现在我们不但需要打印组成部分,还需要保存各个组件到数据库,不仅如此,还需要打印各个组件的价格;此时如果在Unit基类中添加getPrice()和save()方法,也能实现我们想要的功能,但是这样做也存在问题,你并不知道还需要新增什么操作,如果每新增一个操作都用这样的方法来新增,我们的类会变得越来越臃肿。

访问者模式的实现

而访问者模式就是为了解决这个问题的,他把数据结构和作用于结构之上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化,我们来看下面改良过得代码:

/**
  * 抽象基类
  */
  abstract class Unit
  {
    /**
    * 获取名称
    */
    abstract public function getName();

    /**
    * 用来接受访问者对象,回调访问者的visit方法
    * 非常关键的方法
    */
    public function accept(Visitor $visitor)
    {
      $method = visit . get_class($this);
      if (method_exists($visitor, $method)) {
        $visitor->$method($this);
      }
    }
  }

  /**
  * Cpu类
  */
  class Cpu extends Unit
  {
    public function getName()
    {
      return 'i am cpu';
    }
  }

  /**
  * Memory类
  */
  class Memory extends Unit
  {
    public function getName()
    {
      return 'i am memory';
    }
  }

  /**
  * Keyboard类
  */
  class Keyboard extends Unit
  {
    public function getName()
    {
      return 'i am keyboard';
    }
  }
  
  /**
  * Keyboard类
  */
  interface Visitor
  {
    public function visitCpu(Cpu $cpu);
    public function visitMemory(Memory $memory);
    public function visitKeyboard(Keyboard $keyboard);
  }

  /**
  * 
  */
  class PrintVisitor implements Visitor
  {
    public function visitCpu(Cpu $cpu)
    {
      echo "hello, " . $cpu->getName() . "\n";
    }

    public function visitMemory(Memory $memory)
    {
      echo "hello, " . $memory->getName() . "\n";
    }

    public function visitKeyboard(Keyboard $keyboard)
    {
      echo "hello, " . $keyboard->getName() . "\n";
    }
  }

  /**
  * 
  */
  class Computer
  {
    protected $_items = [];

    public function add(Unit $unit)
    {
      $this->_items[] = $unit;
    }
    
    /**
    * 调用各个组件的accept方法
    */
    public function accept(Visitor $visitor)
    {
      foreach ($this->_items as $item) {
        $item->accept($visitor);
      }
    }
  }

  $computer = new Computer();
  $computer->add(new Cpu());
  $computer->add(new Memory());
  $computer->add(new Keyboard());

  $printVisitor = new PrintVisitor();
  $computer->print($printVisitor);

  // 以上的代码将打印出  
  hello, i am cpu
  hello, i am memory
  hello, i am keyboard

总结

经过上面的改良之后,我们要扩展就变得非常容易,如果我们需要新增保存到数据库的方法,可以在新增一个实现了Visitor的类,比如SaveVisitor,在该类中来实现保存的方法,等于我们把该类和该类中的一些操作解藕了出来,而集合了类操作的对象就是访问者。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP-MySQL教程归纳总结
Jun 07 PHP
Php 构造函数construct的前下划线是双的_
Dec 08 PHP
php 操作excel文件的方法小结
Dec 31 PHP
php打造属于自己的MVC框架
Mar 07 PHP
破解.net程序(dll文件)编译和反编译方法
Jan 31 PHP
PHP递归返回值时出现的问题解决办法
Feb 19 PHP
php使用MySQL保存session会话的方法
Jun 26 PHP
使用xampp搭建运行php虚拟主机的详细步骤
Oct 21 PHP
php实现头像上传预览功能
Apr 27 PHP
PHP注释语法规范与命名规范详解篇
Jan 21 PHP
PHP ADODB实现分页功能简单示例
May 25 PHP
关于PHP中interface的用处详解
Jul 26 PHP
PHP接收App端发送文件流的方法
Sep 23 #PHP
适合PHP初学者阅读的4本经典书籍
Sep 23 #PHP
php版微信开发之接收消息,自动判断及回复相应消息的方法
Sep 23 #PHP
php版微信开发Token验证失败或请求URL超时问题的解决方法
Sep 23 #PHP
php版微信公众账号第三方管理工具开发简明教程
Sep 23 #PHP
php版微信公众平台接口参数调试实现判断用户行为的方法
Sep 23 #PHP
php使用CURL模拟GET与POST向微信接口提交及获取数据的方法
Sep 23 #PHP
You might like
php cookie用户登录的详解及实例代码
2017/01/03 PHP
原生js 秒表实现代码
2012/07/24 Javascript
得到jQuery detach()后节点中的某个值实现代码
2013/02/05 Javascript
利用js实现在浏览器状态栏显示访问者在本页停留的时间
2013/12/29 Javascript
ExtJS4给Combobox设置列表中的默认值示例
2014/05/02 Javascript
js操作XML文件的实现方法兼容IE与FireFox
2016/06/25 Javascript
原生js实现ajax方法(超简单)
2016/09/20 Javascript
Bootstrap复选框和单选按钮美化插件(推荐)
2016/11/23 Javascript
详解Jquery 遍历数组之$().each方法与$.each()方法介绍
2017/01/09 Javascript
获取IE浏览器Cookie信息的方法
2017/01/23 Javascript
webpack v4 从dev到prd的方法
2018/04/02 Javascript
浅谈Vue组件及组件的注册方法
2018/08/24 Javascript
Vue-router 切换组件页面时进入进出动画方法
2018/09/01 Javascript
浅谈关于iview表单验证的问题
2018/09/29 Javascript
JS实现的全选、全不选及反选功能【案例】
2019/02/19 Javascript
微信小程序学习笔记之登录API与获取用户信息操作图文详解
2019/03/29 Javascript
JavaScript异步操作的几种常见处理方法实例总结
2020/05/11 Javascript
Javascript实现打鼓效果
2021/01/29 Javascript
[02:39]我与DAC之Newbee.Moogy:从论坛到TI
2018/03/26 DOTA
[03:08]迎霜节狂欢!2018年迎霜节珍藏Ⅰ一览
2018/12/25 DOTA
python字典基本操作实例分析
2015/07/11 Python
PyQt弹出式对话框的常用方法及标准按钮类型
2019/02/27 Python
python3爬虫学习之数据存储txt的案例详解
2019/04/24 Python
Python函数式编程指南:对生成器全面讲解
2019/11/19 Python
浅谈Python中文件夹和python package包的区别
2020/06/01 Python
python中not、and和or的优先级与详细用法介绍
2020/11/03 Python
Cpython解释器中的GIL全局解释器锁
2020/11/09 Python
What's the difference between Debug and Trace class? (Debug类与Trace类有什么区别)
2013/09/10 面试题
学习党的群众路线剖析材料
2014/10/09 职场文书
学生保证书
2015/01/16 职场文书
出纳试用期自我评价
2015/03/10 职场文书
2015年建党94周年演讲稿
2015/03/19 职场文书
幼儿园教师工作总结2015
2015/04/02 职场文书
2015年物业管理工作总结
2015/04/23 职场文书
人生遥控器观后感
2015/06/11 职场文书
手把手教你用SpringBoot将文件打包成zip存放或导出
2021/06/11 Java/Android