浅谈PHP面向对象之访问者模式+组合模式


Posted in PHP onMay 22, 2017

因为原文中延续了组合模式的代码示例来讲访问者模式 所以这里就合并一起来复习了。但主要还是讲访问者模式。顾名思义这个模式会有一个访问者类(就像近期的热播剧“人民的名义”中的检查官,跑到到贪官家里调查取证,查实后就定罪),被访问者类调用访问者类的时候会将自身传递给它使用。

直接看代码:

//被访问者基类

abstract class Unit {
abstract function bombardStrength();//获取单位的攻击力


//这个方法将调用访问者类,并将自身传递给它
function accept(ArmyVisitor $visitor){
$method = "visit" . get_class($this);
$visitor->$method($this);//调用访问者类的方法,这里使用了 "visit" . get_class($this) 组成了方法的名称
}


//按原文的说法是设置一个深度,虽然之后会有调用但这个方法对于理解这个模式不重要可以不用管他(原文示例代码中经常有些跟理解模式原理没太多关系的代码)
protected function setDepth($depth){
$this->depth = $depth;
}

function getDepth(){
return $this->depth;
}
}

 

//弓箭手
class Archer extends Unit{
function bombardStrength(){
return 4;
}
}

//激光炮

class LaserCannonUnit extends Unit{
function bombardStrength(){
return 44;
}
}

//骑兵

class Cavalry extends Unit{
function bombardStrength(){
return 2;//骑兵的攻击力居然比弓箭手低?

}
}

 

//用于组合继承了unit类的实例,并让Army和TroopCarrier类继承removeUnit和addUnit方法,不放基类是因为上述的三个类已经是最小单位了不是一个军事集团removeUnit和addUnit方法对他们没用。

abstract class CompositeUnit extends Unit{
private $units = array();//存放任何继承了unit 类的实例

function getComposite(){ //这个方法主要用于判断当前实例是否是一个 CompositeUnit 类
return $this;
}

protected function units(){
return $this->units;
}

function removeUnit(Unit $unit){//删除一个军事单位
$this->units = array_udiff(
$this->units,array($unit),

function($a,$b){return ($a === $b)?0:1;}

);
}

function addUnit(Unit $unit){//添加一个军事单位
if(in_array($unit,$this->units,true)){
return;
}
$unit->setDepth($this->depth + 1);
$this->units[] = $unit;
}

function bombardStrength(){
$ret = 0;
foreach($this->units as $unit){
$ret +=$unit->bombardStrength();
}
return $ret;
}

function accept(Armyvisitor $visitor){//调用访问者
parent::accept($visitor);//调用基类的accept方法,在第一个客户端代码条用里将会保存军事集团整体的一个信息
foreach($this->units as $thisunit){ //调用军事单位accept方法,在第一个客户端代码条用里将会保存其中每一个军事单位的信息
$thisunit->accept($visitor);
}
}	
}

 

//军队

class Army extends CompositeUnit {

}

//舰队

class TroopCarrier extends CompositeUnit {

}

 

//访问者类

abstract class ArmyVisitor{
abstract function visit(Unit $node);//访问者要执行的业务逻辑
function visitArcher(Archer $node){//其实我觉得对于理解来说这个抽象类有一个抽象方法visit()就够了,原文还多出下面这些方法来绕个圈调用visit

//...... 
$this->visit($node);
}

function visitCavalry(Cavalry $node){

//.......
$this->visit($node);
}

function visitLaserCannonUnit(LaserCannonUnit $node){

//......
$this->visit($node);
}

function visitTroopCarrierUnit(Cavalry $node){

//......
$this->visit($node);
}

function visitArmy(Cavalry $node){

//......
$this->visit($node);
}
}

//这个访问者类主要用于获取并保存被访问者对象的信息
class TextDumpArmyVisitor extends ArmyVisitor {
private $text = "";
function visit(Unit $node){
$ret = "";
$pad = 4 * $node->getDpth();
$ret .= sprintf("%{$pad}s","");
$ret .=get_class($node).": ";
$ret .= "bombard: " . $node->bombardStrength() . "\n";
$this->text .=$ret;
}

function getText(){
return $this->text;
}
}

//用于向每个对象征税的访问者类,客户端代码2中将会调用
class TaxCollectionVisitor extends ArmyVisitor{
private $due=0;
private $report ="";

function visit(Unit $node){
$this->levy($node,1);
}

function visitArcher(Archer $node){//复写了父类的方法,对于不同的单位征收不同的税
$this->levy($node,2);
}

function visitCavalry(Cavalry $node){
$this->levy($node,3);
}

function visitTroopCarrierUnit(TroopCarrierUnit $node){
$this->levy($node,5);
}

private function levy(Unit $unit,$amount){//主要的业务逻辑
$this->report .= "Tax levied for" . get_class($unit);
$this->report .= ": $amount\n";
$this->due +=$amount;
}

function getReport(){
return $this->report;
}

function getTax(){
return $this->due;
}
}


//客户端代码1(获取并输出每个对象的一些信息)
class UnitScript {
static function joinExisting(Unit $newUnit,Unit $occupyingUnit){
$comp;
if(!is_null($com = $occupyingUnit->getComposite())){
$comp->addUnit($newUnit);
} else {
$comp = new Army();
$comp->addUnit($occupyingUnit);
$com->addUnit($newUnit);
}
return $comp;
}
}

 

$main_army = new Army();
UnitScript::joinExisting(new Archer(),$main_army);
UnitScript::joinExisting(new LaserCannonUnit(),$main_army);
UnitScript::joinExisting(new Cavalry(),$main_army);

$textdump = new TextDumpArmyVisitor();
$main_army->accept($textdump);
print $textdump->getText();

 

//客户端代码2(对每个对象征税,最后输出总共征收了多少)
$main_army = new Army();
UnitScript::joinExisting(new Archer(),$main_army);
UnitScript::joinExisting(new LaserCannonUnit(),$main_army);
UnitScript::joinExisting(new Cavalry(),$main_army);
$taxcollector = new TaxCollectionVisitor();
$main_army->accept($taxcollector);
print $taxcollector->getTax();

//上述的代码因为太懒没测试,抱歉! 感兴趣的朋友就自己运行调试一下吧!

以上这篇浅谈PHP面向对象之访问者模式+组合模式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
php数组对百万数据进行排除重复数据的实现代码
Jun 08 PHP
PHP 数据结构 算法 三元组 Triplet
Jul 02 PHP
PHP 杂谈《重构-改善既有代码的设计》之四 简化条件表达式
Apr 09 PHP
php编写的简单页面跳转功能实现代码
Nov 27 PHP
PHP中的日期加减方法示例
Aug 21 PHP
ThinkPHP实现递归无级分类――代码少
Jul 29 PHP
Zend Framework自定义Helper类相关注意事项总结
Mar 14 PHP
PHP面向对象程序设计之命名空间与自动加载类详解
Dec 02 PHP
在云虚拟主机部署thinkphp5项目的步骤详解
Dec 21 PHP
ThinkPHP3.2.3框架实现执行原生SQL语句的方法示例
Apr 03 PHP
微信公众号实现扫码获取微信用户信息(网页授权)
Apr 09 PHP
Thinkphp 框架扩展之驱动扩展实例分析
Apr 27 PHP
php readfile下载大文件失败的解决方法
May 22 #PHP
老生常谈PHP 文件写入和读取(必看篇)
May 22 #PHP
PHP中trait使用方法详细介绍
May 21 #PHP
php写app接口并返回json数据的实例(分享)
May 20 #PHP
PHP实现json_decode不转义中文的方法
May 20 #PHP
Yii框架参数化查询中IN查询只能查询一个的解决方法
May 20 #PHP
Yii框架使用魔术方法实现跨文件调用功能示例
May 20 #PHP
You might like
输入值/表单提交参数过滤有效防止sql注入的方法
2013/12/25 PHP
ThinkPHP3.1.3版本新特性概述
2014/06/19 PHP
PHP使用OB缓存实现静态化功能示例
2019/03/23 PHP
Laravel 简单实现Ajax滚动加载示例
2019/10/22 PHP
yii框架结合charjs统计上一年与当前年数据的方法示例
2020/04/04 PHP
Thinkphp 框架扩展之数据库驱动常用方法小结
2020/04/23 PHP
msn上的tab功能Firefox对childNodes处理的一个BUG
2008/01/21 Javascript
js用闭包遍历树状数组的方法
2014/03/19 Javascript
jQuery遍历Table应用示例
2014/04/09 Javascript
js图片预加载示例
2014/04/30 Javascript
JS+CSS实现模仿浏览器网页字符查找功能的方法
2015/02/26 Javascript
js实现创建删除html元素小结
2015/09/30 Javascript
详解Angular2响应式表单
2017/06/14 Javascript
vue获取DOM元素并设置属性的两种实现方法
2017/09/30 Javascript
浅谈webpack组织模块的原理
2018/03/10 Javascript
vue组件三大核心概念图文详解
2019/05/30 Javascript
vue-cli3添加模式配置多环境变量的方法
2019/06/05 Javascript
Ant Design Vue 添加区分中英文的长度校验功能
2020/01/21 Javascript
Element Alert警告的具体使用方法
2020/07/27 Javascript
使用JS实现鼠标放上图片进行放大离开实现缩小功能
2021/01/27 Javascript
python使用多线程不断刷新网页的方法
2015/03/31 Python
使用python遍历指定城市的一周气温
2017/03/31 Python
Python简单删除列表中相同元素的方法示例
2017/06/12 Python
Python cookbook(数据结构与算法)实现查找两个字典相同点的方法
2018/02/18 Python
Python 查找字符在字符串中的位置实例
2018/05/02 Python
pycharm运行和调试不显示结果的解决方法
2018/11/30 Python
对python mayavi三维绘图的实现详解
2019/01/08 Python
python 如何引入协程和原理分析
2020/11/30 Python
python代码实现猜拳小游戏
2020/11/30 Python
next在python中返回迭代器的实例方法
2020/12/15 Python
法国一家多品牌成衣精品中/高档商店:Graduate Store
2019/08/28 全球购物
生产班组长岗位职责
2014/01/05 职场文书
医学生就业推荐表自我鉴定
2014/03/26 职场文书
退休党员个人对照检查材料思想汇报
2014/09/29 职场文书
社区艾滋病宣传活动总结
2015/05/07 职场文书
Python OpenCV超详细讲解读取图像视频和网络摄像头
2022/04/02 Python