轻松掌握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 相关文章推荐
使用无限生命期Session的方法
Oct 09 PHP
用php+javascript实现二级级联菜单的制作
May 06 PHP
PHP开发工具ZendStudio下Xdebug工具使用说明详解
Nov 11 PHP
php支付宝接口用法分析
Jan 04 PHP
PHP中的闭包(匿名函数)浅析
Feb 07 PHP
PHP 实现代码复用的一个方法 traits新特性
Feb 22 PHP
Zend Framework入门教程之Zend_Db数据库操作详解
Dec 08 PHP
PHP绕过open_basedir限制操作文件的方法
Jun 10 PHP
PHP通过文件路径获取文件名的实例代码
Oct 14 PHP
ThinkPHP5.1表单令牌Token失效问题的解决
Mar 22 PHP
Laravel重定向,a链接跳转,控制器跳转示例
Oct 22 PHP
PHP常用header头定义代码示例汇总
Aug 29 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读取javascript设置的cookies的代码
2010/04/12 PHP
php中array_column函数简单实现方法
2016/07/11 PHP
PHP实现的简单异常处理类示例
2017/05/04 PHP
PHP const定义常量及global定义全局常量实例解析
2020/05/28 PHP
PHP利用curl发送HTTP请求的实例代码
2020/07/09 PHP
Yii实现微信公众号场景二维码的方法实例
2020/08/30 PHP
JavaScript Cookie的读取和写入函数
2009/12/08 Javascript
用客户端js实现带省略号的分页
2013/04/27 Javascript
选择器中含有空格在使用示例及注意事项
2013/07/31 Javascript
JavaScript通过正则表达式实现表单验证电话号码
2014/03/07 Javascript
javascript中日期函数new Date()的浏览器兼容性问题
2015/09/05 Javascript
jQuery 判断是否包含在数组中Array[]的方法
2016/08/03 Javascript
细数JavaScript 一个等号,两个等号,三个等号的区别
2016/10/09 Javascript
react高阶组件经典应用之权限控制详解
2017/09/07 Javascript
使用JavaScript中的lodash编写双色球效果
2018/06/24 Javascript
在Bootstrap开发框架中使用dataTable直接录入表格行数据的方法
2018/10/25 Javascript
在layui tab控件中载入外部html页面的方法
2019/09/04 Javascript
ant design vue导航菜单与路由配置操作
2020/10/28 Javascript
[01:02]DOTA2上海特锦赛SHOWOPEN
2016/03/25 DOTA
Python调用SQLPlus来操作和解析Oracle数据库的方法
2016/04/09 Python
浅谈Python爬取网页的编码处理
2016/11/04 Python
python主线程捕获子线程的方法
2018/06/17 Python
python计算列表内各元素的个数实例
2018/06/29 Python
Python分支语句与循环语句应用实例分析
2019/05/07 Python
Pytorch的mean和std调查实例
2020/01/02 Python
Puma印度官网:德国运动品牌
2019/10/06 全球购物
优秀学生干部个人的自我评价
2013/10/04 职场文书
体育教师工作总结的自我评价
2013/10/10 职场文书
大学毕业生最详细的自我评价分享
2013/11/18 职场文书
怎样写好自我鉴定
2013/12/04 职场文书
保险公司晨会主持词
2014/03/22 职场文书
消防安全责任书
2014/04/14 职场文书
个人授权委托书范本
2014/09/14 职场文书
意外死亡赔偿协议书
2014/10/14 职场文书
2015年度合同管理工作总结
2015/05/22 职场文书
小学生六年级作文之关于感恩
2019/08/16 职场文书