轻松掌握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 相关文章推荐
如何过滤高亮显示非法字符
Oct 09 PHP
discuz安全提问算法
Jun 06 PHP
PHP的范围解析操作符(::)的含义分析说明
Jul 03 PHP
mongo Table类文件 获取MongoCursor(游标)的实现方法分析
Jul 01 PHP
php接口和抽象类使用示例详解
Mar 02 PHP
php站内搜索关键词变亮的实现方法
Dec 30 PHP
php中session与cookie的比较
Jan 27 PHP
ThinkPHP模板Volist标签嵌套循环输出多维数组的方法
Mar 23 PHP
php实现XML和数组的相互转化功能示例
Feb 08 PHP
thinkPHP5框架闭包函数与子查询传参用法示例
Aug 02 PHP
PHP array_reduce()函数的应用解析
Oct 28 PHP
PHP常用字符串函数用法实例总结
Jun 04 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
各种咖啡的英文名子是什么
2021/03/03 新手入门
微信公众号点击菜单即可打开并登录微站的实现方法
2014/11/14 PHP
Zend Framework教程之分发器Zend_Controller_Dispatcher用法详解
2016/03/07 PHP
laravel框架中控制器的创建和使用方法分析
2019/11/23 PHP
jQuery点击弹出下拉菜单的小例子
2013/08/01 Javascript
Extjs的FileUploadField文件上传出现了两个上传按钮
2014/04/29 Javascript
JS实现的表格行鼠标点击高亮效果代码
2015/11/27 Javascript
基于RequireJS和JQuery的模块化编程——常见问题全面解析
2016/04/14 Javascript
探寻JavaScript中this指针指向
2016/04/23 Javascript
全屏滚动插件fullPage.js使用实例解析
2016/10/21 Javascript
分享19个JavaScript 有用的简写写法
2017/07/07 Javascript
echarts同一页面中四个图表切换的js数据交互方法示例
2018/07/03 Javascript
微信小程序视图控件与bindtap之间的问题的解决
2019/04/08 Javascript
Vue中UI组件库之Vuex与虚拟服务器初识
2019/05/07 Javascript
微信小程序文字显示换行问题
2019/07/28 Javascript
Vue仿微信app页面跳转动画效果
2019/08/21 Javascript
[28:48]《真视界》- 2017年国际邀请赛
2017/09/27 DOTA
在Python中测试访问同一数据的竞争条件的方法
2015/04/23 Python
python入门基础之用户输入与模块初认识
2016/11/14 Python
python代码实现ID3决策树算法
2017/12/20 Python
python合并同类型excel表格的方法
2018/04/01 Python
django 删除数据库表后重新同步的方法
2018/05/27 Python
python微信公众号之关键词自动回复
2018/06/15 Python
Python中Numpy mat的使用详解
2019/05/24 Python
Django REST framework 分页的实现代码
2019/06/19 Python
基于Python的ModbusTCP客户端实现详解
2019/07/13 Python
Python下opencv图像阈值处理的使用笔记
2019/08/04 Python
Django 拼接两个queryset 或是两个不可以相加的对象实例
2020/03/28 Python
医药营销个人求职信
2014/04/12 职场文书
反邪教标语
2014/06/23 职场文书
学习教师法的心得体会
2014/09/03 职场文书
交通事故被告代理词
2015/05/23 职场文书
天鹅湖观后感
2015/06/09 职场文书
从贫穷到富有,是知识技能和学习力的差别
2019/08/20 职场文书
导游词之五台山
2019/10/11 职场文书
Python matplotlib多个子图绘制整合
2022/04/13 Python