轻松掌握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 5.3新特性命名空间规则解析及高级功能
Mar 11 PHP
php的memcached客户端memcached
Jun 14 PHP
PHP 过滤页面中的BOM(实现代码)
Jun 29 PHP
php实现MD5加密16位(不要默认的32位)
Aug 12 PHP
PHP 抽象方法与抽象类abstract关键字介绍及应用
Oct 16 PHP
PHP实现冒泡排序的简单实例
May 26 PHP
PHP实现链式操作的原理详解
Sep 16 PHP
Ajax实现对静态页面的文章访问统计功能示例
Oct 10 PHP
PHP实现根据数组的值进行分组的方法
Apr 20 PHP
PHP精确到毫秒秒杀倒计时实例详解
Mar 14 PHP
php和redis实现秒杀活动的流程
Jul 17 PHP
PHP单元测试配置与使用方法详解
Dec 27 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连接mssql:pdo odbc sql server
2011/07/20 PHP
Docker 如何布置PHP开发环境
2016/06/21 PHP
ucenter中词语过滤原理分析
2016/07/13 PHP
PHP简单预防sql注入的方法
2016/09/27 PHP
javascript图片相似度算法实现 js实现直方图和向量算法
2014/01/14 Javascript
javascript页面加载完执行事件代码
2014/02/11 Javascript
jquery滚动到顶部底部代码
2015/04/20 Javascript
JavaScript几种数组去掉重复值的方法推荐
2016/04/12 Javascript
使用jQuery判断浏览器滚动条位置的方法
2016/05/30 Javascript
JS弹出窗口插件zDialog简单用法示例
2016/06/12 Javascript
Angular.Js之Scope作用域的学习教程
2017/04/27 Javascript
Node.js如何使用Diffie-Hellman密钥交换算法详解
2017/09/05 Javascript
node.js到底要不要加分号浅析
2018/07/11 Javascript
Vue实现按钮旋转和移动位置的实例代码
2018/08/09 Javascript
JS箭头函数和常规函数之间的区别实例分析【 5 个区别】
2020/05/27 Javascript
[48:20]OpTic vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
[57:55]EG vs Fnatic 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
Python中操作mysql的pymysql模块详解
2016/09/13 Python
Python使用MD5加密算法对字符串进行加密操作示例
2018/03/30 Python
pycharm 在windows上编辑代码用linux执行配置的方法
2018/10/27 Python
python删除文件夹下相同文件和无法打开的图片
2019/07/16 Python
Flask框架路由和视图用法实例分析
2019/11/07 Python
使用 Python 在京东上抢口罩的思路详解
2020/02/27 Python
python 实现在无序数组中找到中位数方法
2020/03/03 Python
python同时遍历两个list用法说明
2020/05/02 Python
Python request中文乱码问题解决方案
2020/09/17 Python
python连接mongodb数据库操作数据示例
2020/11/30 Python
你可能不熟练的十个前端HTML5经典面试题
2018/07/03 HTML / CSS
美国知名的百货清仓店:Neiman Marcus Last Call
2016/08/03 全球购物
大学生求职简历的自我评价
2013/10/21 职场文书
销售行政专员岗位职责
2014/06/10 职场文书
药店促销活动策划方案
2014/08/24 职场文书
优秀少先队员事迹材料
2014/12/24 职场文书
三八妇女节新闻稿
2015/07/17 职场文书
《蚂蚁和蝈蝈》教学反思
2016/02/22 职场文书
解决使用了nginx获取IP地址都是127.0.0.1 的问题
2021/09/25 Servers