轻松掌握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 相关文章推荐
在windows iis5下安装php4.0+mysql之我见
Oct 09 PHP
解析PHP中ob_start()函数的用法
Jun 24 PHP
php生成缩略图示例代码分享(使用gd库实现)
Jan 20 PHP
php获取网页标题和内容函数(不包含html标签)
Feb 03 PHP
使用PHP实现阻止用户上传成人照片或者裸照
Dec 25 PHP
php array_merge函数使用需要注意的一个问题
Mar 30 PHP
基于PHP实现的事件机制实例分析
Jun 18 PHP
详解Grunt插件之LiveReload实现页面自动刷新(两种方案)
Jul 31 PHP
PHP实现递归无限级分类
Oct 22 PHP
详解php框架Yaf路由重写
Jun 20 PHP
实例分析基于PHP微信网页获取用户信息
Nov 24 PHP
laravel 验证错误信息到 blade模板的方法
Sep 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利用腾讯ip分享计划获取地理位置示例分享
2014/01/20 PHP
php中smarty模板条件判断用法实例
2015/06/11 PHP
Yii框架实现记录日志到自定义文件的方法
2017/05/23 PHP
php注册系统和使用Xajax即时验证用户名是否被占用
2017/08/31 PHP
php生成条形码的图片的实例详解
2017/09/13 PHP
laravel-admin 管理平台获取当前登陆用户信息的例子
2019/10/08 PHP
js防止表单重复提交实现代码
2012/09/05 Javascript
jquery在Chrome下获取图片的长宽问题解决
2013/03/20 Javascript
onkeypress字符按键兼容所有浏览器使用介绍
2013/04/24 Javascript
JS实现向表格中动态添加行的方法
2015/03/30 Javascript
jQuery插件Slider Revolution实现响应动画滑动图片切换效果
2015/06/05 Javascript
AngularJS实现表单手动验证和表单自动验证
2015/12/09 Javascript
JS函数的几种定义方式分析
2015/12/17 Javascript
jquery遍历json对象集合详解
2016/05/18 Javascript
BootStrop前端框架入门教程详解
2016/12/25 Javascript
zTree实现节点修改的实时刷新功能
2017/03/20 Javascript
Vue-cli-webpack搭建斗鱼直播步骤详解
2017/11/17 Javascript
JS引用传递与值传递的区别与用法分析
2018/06/01 Javascript
vue-cli3搭建项目的详细步骤
2018/12/05 Javascript
[02:51]DOTA2战队出征照拍摄花絮 TI3明星化身时尚男模
2013/07/22 DOTA
Python中Django框架利用url来控制登录的方法
2015/07/25 Python
python虚拟环境virtualenv的安装与使用
2017/09/21 Python
Python cookbook(数据结构与算法)实现查找两个字典相同点的方法
2018/02/18 Python
详解基于django实现的webssh简单例子
2018/07/17 Python
Django xadmin开启搜索功能的实现
2019/11/15 Python
Python实现检测文件的MD5值来查找重复文件案例
2020/03/12 Python
Java中实现多态的机制是什么?
2014/12/07 面试题
C++面试题目
2013/06/25 面试题
技术总监个人的自我评价范文
2013/12/18 职场文书
《诺贝尔》教学反思
2014/02/17 职场文书
知名企业招聘广告词大全
2014/03/18 职场文书
保密工作责任书
2014/04/16 职场文书
2014教师党员自我评议(5篇)
2014/09/20 职场文书
离婚协议书范本(2014版)
2014/09/28 职场文书
2014年环卫工作总结
2014/11/22 职场文书
结婚喜宴迎宾词
2015/08/10 职场文书