轻松掌握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里的JS打印函数
Oct 09 PHP
用文本文件实现的动态实时发布新闻的程序
Oct 09 PHP
如何使用PHP中的字符串函数
Nov 24 PHP
模拟flock实现文件锁定
Feb 14 PHP
php实现的简单压缩英文字符串的代码
Apr 24 PHP
实现在同一方法中获取当前方法中新赋值的session值解决方法
Jun 26 PHP
推荐一款MAC OS X 下php集成开发环境mamp
Nov 08 PHP
PHP正则表达式之捕获组与非捕获组
Nov 06 PHP
php获取文件名称和扩展名的方法
Feb 07 PHP
php利用imagemagick实现复古老照片效果实例
Feb 16 PHP
深入讲解PHP的对象注入(Object Injection)
Mar 01 PHP
使用php的mail()函数实现发送邮件功能
Jun 03 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
用函数读出数据表内容放入二维数组
2006/10/09 PHP
PHP中查询SQL Server或Sybase时TEXT字段被截断的解决方法
2009/03/10 PHP
PHP变量内存分配问题记录整理
2013/11/27 PHP
PHP模拟asp.net的StringBuilder类实现方法
2015/08/08 PHP
PHP使用SWOOLE扩展实现定时同步 MySQL 数据
2017/04/09 PHP
laravel批量生成假数据的方法
2019/10/09 PHP
javascript css float属性的特殊写法
2008/11/13 Javascript
Jquery插件写法笔记整理
2012/09/06 Javascript
Javascript中的异步编程规范Promises/A详细介绍
2014/06/06 Javascript
js实现仿Windows风格选项卡和按钮效果实例
2015/05/13 Javascript
jQuery 1.9.1源码分析系列(十五)之动画处理
2015/12/03 Javascript
微信开发 微信授权详解
2016/10/21 Javascript
基于slideout.js实现移动端侧边栏滑动特效
2016/11/28 Javascript
详解js树形控件—zTree使用总结
2016/12/28 Javascript
使用JavaScript触发过渡效果的方法
2017/01/19 Javascript
JS实现经典的中国地区三级联动下拉菜单功能实例【测试可用】
2017/06/06 Javascript
python 解析html之BeautifulSoup
2009/07/07 Python
Python内置函数bin() oct()等实现进制转换
2012/12/30 Python
python求素数示例分享
2014/02/16 Python
Python中index()和seek()的用法(详解)
2017/04/27 Python
python anaconda 安装 环境变量 升级 以及特殊库安装的方法
2017/06/21 Python
基于Python开发chrome插件的方法分析
2018/07/07 Python
Python猜数字算法题详解
2020/03/01 Python
python简单利用字典破解zip文件口令
2020/09/07 Python
结合CSS3的布局新特征谈谈常见布局方法
2016/01/22 HTML / CSS
使用canvas生成含有微信头像的邀请海报没有微信头像问题
2019/10/29 HTML / CSS
美国现代家具和家居商店:Apt2B
2016/08/29 全球购物
德国孕妇装和婴童服装网上商店:bellybutton
2018/04/12 全球购物
德国网上花店:Valentins
2018/08/15 全球购物
支行行长竞聘报告
2014/11/06 职场文书
道歉的话怎么说
2015/05/12 职场文书
2015年除四害工作总结
2015/07/23 职场文书
初中班主任教育随笔
2015/08/15 职场文书
初中班主任工作随笔
2015/08/15 职场文书
开学第一周日记(三篇范文)
2019/08/23 职场文书
话题作文之财富(600字)
2019/12/03 职场文书