浅谈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 相关文章推荐
图形数字验证代码
Oct 09 PHP
IIS php环境配置PHP5 MySQL5 ZendOptimizer phpmyadmin安装与配置
Nov 18 PHP
php使用mysqli向数据库添加数据的方法
Mar 20 PHP
php格式化电话号码的方法
Apr 24 PHP
在WordPress中使用wp_count_posts函数来统计文章数量
Jan 05 PHP
CI框架实现cookie登陆的方法详解
May 18 PHP
php通过两层过滤获取留言内容的方法
Jul 11 PHP
php 读取输出其他文件的实现方法
Jul 26 PHP
Yii2框架RESTful API 格式化响应,授权认证和速率限制三部分详解
Nov 10 PHP
php 中奖概率算法实现代码
Jan 25 PHP
PHP二维索引数组的遍历实例分析【2种方式】
Jun 24 PHP
ThinkPHP 5 AJAX跨域请求头设置实现过程解析
Oct 28 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
CodeIgniter使用phpcms模板引擎
2013/11/12 PHP
php Imagick获取图片RGB颜色值
2014/07/28 PHP
php隐藏实际地址的文件下载方法
2015/04/18 PHP
PHP面向对象五大原则之单一职责原则(SRP)详解
2018/04/04 PHP
PHP var关键字相关原理及使用实例解析
2020/07/11 PHP
用window.location.href实现刷新另个框架页面
2007/03/07 Javascript
使用Javascript接收get传递的值的代码
2011/11/30 Javascript
ASP.NET jQuery 实例3 (在TextBox里面阻止复制、剪切和粘贴事件)
2012/01/13 Javascript
微信企业号开发之微信考勤Cookies的使用
2015/09/11 Javascript
浅谈如何使用 webpack 优化资源
2017/10/20 Javascript
详解webpack的proxyTable无效的解决方案
2018/06/15 Javascript
详解Vue中watch的详细用法
2018/11/28 Javascript
利用vue重构有赞商城的思路以及总结整理
2019/02/21 Javascript
vue踩坑记-在项目中安装依赖模块npm install报错
2019/04/02 Javascript
js回文数的4种判断方法示例
2019/06/04 Javascript
JS实现多选框的操作
2020/06/24 Javascript
纯JS开发baguetteBox.js响应式画廊插件
2020/06/28 Javascript
[52:08]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#2Fnatic VS OG第一局
2016/03/05 DOTA
一个简单的python程序实例(通讯录)
2013/11/29 Python
python pdb调试方法分享
2014/01/21 Python
Python实现的堆排序算法原理与用法实例分析
2017/11/22 Python
python八皇后问题的解决方法
2018/09/27 Python
Python学习笔记之pandas索引列、过滤、分组、求和功能示例
2019/06/03 Python
PyTorch的SoftMax交叉熵损失和梯度用法
2020/01/15 Python
很酷的HTML5电子书翻页动画特效
2016/02/25 HTML / CSS
林清轩官方网站:山茶花润肤油开创者
2016/10/26 全球购物
运动会横幅标语
2014/06/17 职场文书
老公给老婆的检讨书(精华篇)
2014/10/18 职场文书
党的作风建设心得体会
2014/10/22 职场文书
违反交通安全法检讨书
2014/10/24 职场文书
2015教师见习期工作总结
2014/12/12 职场文书
2014小学年度工作总结
2014/12/20 职场文书
民主评议党员个人总结
2015/02/13 职场文书
2015年“世界无车日”活动方案
2015/05/06 职场文书
Vue3.0中Ref与Reactive的区别示例详析
2021/07/07 Vue.js
Python实现Excel文件的合并(以新冠疫情数据为例)
2022/03/20 Python