浅谈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 相关文章推荐
mysql From_unixtime及UNIX_TIMESTAMP及DATE_FORMAT日期函数
Mar 21 PHP
zend framework多模块多布局配置
Feb 26 PHP
PHP $_FILES函数详解
Mar 09 PHP
php 团购折扣计算公式
Nov 24 PHP
第二章 PHP入门基础之php代码写法
Dec 30 PHP
win2003服务器使用WPS的COM组件的一些问题解决方法
Jan 11 PHP
解析PHP将对象转换成数组的方法(兼容多维数组类型)
Jun 21 PHP
微信API接口大全
Apr 15 PHP
PHP文件下载实例代码浅析
Aug 17 PHP
Thinkphp结合ajaxFileUpload实现异步图片传输示例
Mar 13 PHP
php把字符串指定字符分割成数组的方法
Mar 12 PHP
PHP curl批处理及多请求并发实现方法分析
Aug 15 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
PHP5中MVC结构学习
2006/10/09 PHP
PHP6 先修班 JSON实例代码
2008/08/23 PHP
jQuery+Ajax+PHP“喜欢”评级功能实现代码
2015/10/08 PHP
PHP实现的curl批量请求操作示例
2018/06/06 PHP
javascript SocialHistory 检查访问者是否访问过某站点
2008/08/02 Javascript
javascript 框架小结 个人工作经验
2009/06/13 Javascript
网页禁用右键实现代码(JavaScript代码)
2009/10/29 Javascript
Jquery CheckBox全选方法代码附js checkbox全选反选代码
2010/06/09 Javascript
Jquery插件easyUi表单验证提交(示例代码)
2013/12/30 Javascript
JavaScript判断数组是否包含指定元素的方法
2015/07/01 Javascript
js判断复选框是否选中及选中个数的实现代码
2016/05/30 Javascript
使用 jQuery.ajax 上传带文件的表单遇到的问题
2016/10/31 Javascript
JavaScript的兼容性与调试技巧
2016/11/22 Javascript
AngularJS实现使用路由切换视图的方法
2017/01/24 Javascript
微信小程序 本地图片按照屏幕尺寸处理
2017/08/04 Javascript
手把手教你用Node.js爬虫爬取网站数据的方法
2018/07/05 Javascript
node.js到底要不要加分号浅析
2018/07/11 Javascript
React 全自动数据表格组件——BodeGrid的实现思路
2019/06/12 Javascript
监控微信小程序中的慢HTTP请求过程详解
2019/07/05 Javascript
vue路由传参页面刷新参数丢失问题解决方案
2019/10/08 Javascript
[50:28]LGD女子学院第三期 DOTA2复仇之魂教学
2013/12/24 DOTA
[01:03]DOTA2新的征程 你的脚印值得踏上
2014/08/13 DOTA
[03:49]辉夜杯现场龙骑士COSER秀情商“我喜欢芬队!”
2015/12/27 DOTA
Python 调用DLL操作抄表机
2009/01/12 Python
python使用wxpython开发简单记事本的方法
2015/05/20 Python
python实现随机调用一个浏览器打开网页
2018/04/21 Python
详解python配置虚拟环境
2019/04/08 Python
pytorch 多分类问题,计算百分比操作
2020/07/09 Python
Python+unittest+DDT实现数据驱动测试
2020/11/30 Python
美国领先的户外服装与装备用品店:Moosejaw
2016/08/25 全球购物
银行演讲稿范文
2014/01/03 职场文书
业务员的岗位职责
2014/03/15 职场文书
初中三好学生自我鉴定
2014/04/07 职场文书
特此通知格式
2015/04/27 职场文书
2015年留守儿童工作总结
2015/05/22 职场文书
Java后端 Dubbo retries 超时重试机制的解决方案
2022/04/14 Java/Android