轻松掌握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 相关文章推荐
特详细的PHPMYADMIN简明安装教程
Aug 01 PHP
php 获得汉字拼音首字母的函数
Aug 01 PHP
从康盛产品(discuz)提取出来的模板类
Jun 28 PHP
PHP中获取内网用户MAC地址(WINDOWS/linux)的实现代码
Aug 11 PHP
PHP判断数据库中的记录是否存在的方法
Nov 14 PHP
PHP扩展Memcache分布式部署方案
Dec 06 PHP
PHP入门教程之面向对象基本概念实例分析
Sep 11 PHP
PHP实现向关联数组指定的Key之前插入元素的方法
Jun 06 PHP
PHP实现的mysql操作类【MySQL与MySQLi方式】
Oct 07 PHP
php 二维数组快速排序算法的实现代码
Oct 17 PHP
PHPStudy下如何为Apache安装SSL证书的方法步骤
Jan 23 PHP
php探针使用原理和技巧讲解
Sep 17 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
日本十大最佳动漫,全都是二次元的神级作品
2019/10/05 日漫
IIS下配置Php+Mysql+zend的图文教程
2006/12/08 PHP
php+mysql开源XNA 聚合程序发布 下载
2007/07/13 PHP
PHP字符串的编码问题的详细介绍
2013/04/27 PHP
php计算数组相同值出现次数的代码(array_count_values)
2015/01/20 PHP
php实现改变图片直接打开为下载的方法
2015/04/14 PHP
[原创]PHP实现字节数Byte转换为KB、MB、GB、TB的方法
2017/08/31 PHP
关于PHP虚拟主机概念及如何选择稳定的PHP虚拟主机
2018/11/20 PHP
php和vue配合使用技巧和方法
2019/05/09 PHP
php实例化一个类的具体方法
2019/09/19 PHP
PHP使用观察者模式处理异常信息的方法详解
2019/09/24 PHP
用javascript实现在小方框中浏览大图的代码
2007/08/14 Javascript
JavaScript之引用类型介绍
2012/08/10 Javascript
js日期插件dateHelp获取本月、三个月、今年的日期
2016/03/07 Javascript
jqGrid 学习笔记整理——进阶篇(一 )
2016/04/17 Javascript
Javascript中关于Array.filter()的妙用详解
2016/12/04 Javascript
JavaScript封装的常用工具类库bee.js用法详解【经典类库】
2018/09/03 Javascript
原生javascript的ajax请求及后台PHP响应操作示例
2020/02/24 Javascript
手把手教您实现react异步加载高阶组件
2020/04/07 Javascript
[33:42]LGD vs OG 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python Requests 基础入门
2016/04/07 Python
python删除某个字符
2018/03/19 Python
Python中字符串String的基本内置函数与过滤字符模块函数的基本用法
2019/05/27 Python
在Keras中实现保存和加载权重及模型结构
2020/06/15 Python
python中get和post有什么区别
2020/06/19 Python
学生如何注册Pycharm专业版以及pycharm的安装
2020/09/24 Python
使用canvas绘制贝塞尔曲线
2014/12/17 HTML / CSS
canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器)
2018/01/10 HTML / CSS
教育孩子心得体会
2014/01/01 职场文书
高中历史教学反思
2014/02/08 职场文书
青年志愿者先进事迹
2014/05/06 职场文书
2014年反腐倡廉工作总结
2014/12/05 职场文书
2016年大学自主招生自荐信范文
2015/03/24 职场文书
求职自我评价参考范文
2019/05/16 职场文书
Pytorch distributed 多卡并行载入模型操作
2021/06/05 Python
Redis特殊数据类型Geospatial地理空间
2022/06/01 Redis