浅谈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 将bmp图片转为jpg等其他任意格式的图片
Jun 21 PHP
php流量统计功能的实现代码
Sep 29 PHP
php自定义函数截取汉字长度
May 15 PHP
thinkphp循环结构用法实例
Nov 24 PHP
php截取html字符串及自动补全html标签的方法
Jan 15 PHP
php关联数组快速排序的方法
Apr 17 PHP
如何在HTML 中嵌入 PHP 代码
May 13 PHP
PHP封装的Twitter访问类实例
Jul 18 PHP
php中各种定义变量的方法小结
Oct 18 PHP
thinkPHP框架实现生成条形码的方法示例
Jun 06 PHP
laravel config文件配置全局变量的例子
Oct 13 PHP
php把文件设置为插件的技巧方法
Feb 03 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
怎样在php中使用PDF文档功能
2006/10/09 PHP
mysql 全文搜索 技巧
2007/04/27 PHP
php 在文件指定行插入数据的代码
2010/05/08 PHP
PHP中使用mktime获取时间戳的一个黑色幽默分析
2012/05/31 PHP
PHP导入导出Excel代码
2015/07/07 PHP
php web环境和命令行环境下查找php.ini的位置
2019/07/17 PHP
javascript 数组的方法集合
2008/06/05 Javascript
js iframe跨域访问(同主域/非同主域)分别深入介绍
2013/01/24 Javascript
js限制checkbox选中个数以限制六个为例
2014/07/15 Javascript
使用ngView配合AngularJS应用实现动画效果的方法
2015/06/19 Javascript
Express实现前端后端通信上传图片之存储数据库(mysql)傻瓜式教程(一)
2015/12/10 Javascript
JavaScript html5 canvas画布中删除一个块区域的方法
2016/01/26 Javascript
ichart.js绘制虚线、平均分虚线效果的实现代码
2016/05/05 Javascript
jquery学习笔记之无new构建详解
2017/12/07 jQuery
elementui的默认样式修改方法
2018/02/23 Javascript
解决webpack+Vue引入iView找不到字体文件的问题
2018/09/28 Javascript
Vue触发隐藏input file的方法实例详解
2019/08/14 Javascript
el-form 多层级表单的实现示例
2020/09/10 Javascript
Python编写百度贴吧的简单爬虫
2015/04/02 Python
编写Python脚本来获取mp3文件tag信息的教程
2015/05/04 Python
python爬虫使用cookie登录详解
2017/12/27 Python
python 内置模块详解
2019/01/01 Python
解决python replace函数替换无效问题
2020/01/18 Python
pip安装tensorflow的坑的解决
2020/04/19 Python
CSS3 开发工具收集
2010/04/17 HTML / CSS
Canvas环形饼图与手势控制的实现代码
2019/11/08 HTML / CSS
Expedia加拿大官方网站:加拿大最大的在线旅游提供商
2017/12/31 全球购物
Kneipp克奈圃美国官网:德国百年精油配方的传承
2018/02/07 全球购物
军人违纪检讨书
2014/02/04 职场文书
2014新课程改革心得体会
2014/03/10 职场文书
2014年党务公开方案
2014/05/08 职场文书
大四优秀党员个人民主评议
2014/09/19 职场文书
公司总经理岗位职责
2015/04/01 职场文书
2015年司机工作总结
2015/04/23 职场文书
关于军训的感想
2015/08/07 职场文书
在python中读取和写入CSV文件详情
2022/06/28 Python