轻松掌握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 getimagesize 上传图片的长度和宽度检测代码
May 15 PHP
php做下载文件的实现代码及文件名中乱码解决方法
Feb 03 PHP
ThinkPHP3.1新特性之动态设置自动完成和自动验证示例
Jun 19 PHP
PHP命名空间(namespace)的动态访问及使用技巧
Aug 18 PHP
linux中cd命令使用详解
Jan 08 PHP
CodeIgniter框架常见用法工作总结
Mar 16 PHP
php使用curl实现ftp文件下载功能
May 16 PHP
php实现的错误处理封装类实例
Jun 20 PHP
php+js实现裁剪任意形状图片
Oct 31 PHP
PHP时间戳和日期相互转换操作实例小结
Dec 18 PHP
php的RSA加密解密算法原理与用法分析
Jan 23 PHP
Laravel框架源码解析之模型Model原理与用法解析
May 14 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比较操作符的安全问题
2015/12/03 PHP
tp5(thinkPHP5)框架数据库Db增删改查常见操作总结
2019/01/10 PHP
Yii2.0框架实现带分页的多条件搜索功能示例
2019/02/20 PHP
详解使用php-cs-fixer格式化代码
2020/09/16 PHP
javascript 面向对象全新理练之继承与多态
2009/12/03 Javascript
jQuery实现鼠标划过添加和删除class的方法
2015/06/26 Javascript
js+css实现有立体感的按钮式文字竖排菜单效果
2015/09/01 Javascript
js下将金额数字每三位一逗号分隔
2016/02/19 Javascript
深入浅析AngularJS中的一次性数据绑定 (bindonce)
2017/05/11 Javascript
浅谈vue实现数据监听的函数 Object.defineProperty
2017/06/08 Javascript
node.js中http模块和url模块的简单介绍
2017/10/06 Javascript
Vue加载json文件的方法简单示例
2019/01/28 Javascript
Vue中关闭弹窗组件时销毁并隐藏操作
2020/09/01 Javascript
JavaScript实现简单动态表格
2020/12/02 Javascript
python实现网页链接提取的方法分享
2014/02/25 Python
Python实现设置windows桌面壁纸代码分享
2015/03/28 Python
python实现按行切分文本文件的方法
2016/04/18 Python
使用python获取csv文本的某行或某列数据的实例
2018/04/03 Python
Ubuntu下使用python读取doc和docx文档的内容方法
2018/05/08 Python
《与孩子一起学编程》python自测题
2018/05/27 Python
Django自定义列表 models字段显示方式
2020/04/03 Python
jupyter notebook 调用环境中的Keras或者pytorch教程
2020/04/14 Python
解决windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的问题
2020/05/20 Python
使用keras实现孪生网络中的权值共享教程
2020/06/11 Python
简单了解Django项目应用创建过程
2020/07/06 Python
CSS3混合模式mix-blend-mode/background-blend-mode简介
2018/03/15 HTML / CSS
详解HTML5中的Communication API基本使用方法
2016/01/29 HTML / CSS
浅谈HTML5新增和废弃的标签
2019/04/28 HTML / CSS
美国第二大团购网站:LivingSocial
2016/07/24 全球购物
澳大利亚购买最佳炊具品牌网站:Cookware Brands
2019/02/16 全球购物
料理师求职信
2014/01/30 职场文书
房产代理公证处委托书
2014/04/04 职场文书
2014年幼儿园后勤工作总结
2014/11/10 职场文书
pandas求平均数和中位数的方法实例
2021/08/04 Python
各种货币符号快捷输入
2022/02/17 杂记
MySQL 表锁定 LOCK和UNLOCK TABLES的 SQL语法
2022/04/18 MySQL