浅谈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开发环境配置记录
Jan 14 PHP
php中判断数组相等的方法以及数组运算符介绍
Mar 30 PHP
四个常见html网页乱码问题及解决办法
Sep 08 PHP
双冒号 ::在PHP中的使用情况
Nov 05 PHP
PHP代码维护,重构变困难的4种原因分析
Jan 25 PHP
PHP自定义函数获取URL中一级域名的方法
Aug 23 PHP
验证坐标在某坐标区域内php代码
Oct 08 PHP
thinkPHP中配置的读取与C方法详解
Dec 05 PHP
php实现保存周期为1天的购物车类
Jul 07 PHP
记录Yii2框架开发微信公众号遇到的问题及解决方法
Jul 20 PHP
Yii2框架配置文件(Application属性)与调试技巧实例分析
May 27 PHP
php使用yield对性能提升的测试实例分析
Sep 19 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数组
2006/10/09 PHP
php visitFile()遍历指定文件夹函数
2010/08/21 PHP
使用配置类定义Codeigniter全局变量
2014/06/12 PHP
php使用pdo连接报错Connection failed SQLSTATE的解决方法
2014/12/15 PHP
PHP实现Huffman编码/解码的示例代码
2018/04/20 PHP
javascript动画浅析
2012/08/30 Javascript
使用jquery mobile做幻灯播放效果实现步骤
2013/01/04 Javascript
JS获得图片alt信息的方法
2015/04/01 Javascript
jQuery事件绑定与解除绑定实现方法
2015/04/15 Javascript
Ionic2系列之使用DeepLinker实现指定页面URL
2016/11/21 Javascript
JS组件系列之JS组件封装过程详解
2017/04/28 Javascript
vue组件开发props验证的实现
2019/02/12 Javascript
JS实现json数组排序操作实例分析
2019/10/28 Javascript
vue-cli3单页构建大型项目方案
2020/04/07 Javascript
JavaScript对象字面量和构造函数原理与用法详解
2020/04/18 Javascript
JavaScript缓动动画函数的封装方法
2020/11/25 Javascript
详解Python 模拟实现生产者消费者模式的实例
2017/08/10 Python
python调用tcpdump抓包过滤的方法
2018/07/18 Python
python 对多个csv文件分别进行处理的方法
2019/01/07 Python
浅析Python 读取图像文件的性能对比
2019/03/07 Python
Pandas 重塑(stack)和轴向旋转(pivot)的实现
2019/07/22 Python
python pygame实现挡板弹球游戏
2019/11/25 Python
keras load model时出现Missing Layer错误的解决方式
2020/06/11 Python
Pycharm连接gitlab实现过程图解
2020/09/01 Python
python 进程池pool使用详解
2020/10/15 Python
Python通过字典映射函数实现switch
2020/11/06 Python
pycharm最新激活码有效期至2100年(亲测可用)
2021/02/05 Python
优秀毕业生求职信
2014/06/05 职场文书
乡镇消防安全责任书
2014/07/23 职场文书
司机岗位职责范本
2015/04/10 职场文书
公司放假通知怎么写
2015/04/15 职场文书
读书笔记格式
2015/07/02 职场文书
致接力运动员加油稿
2015/07/21 职场文书
Python中X[:,0]和X[:,1]的用法
2021/05/10 Python
vue使用Google Recaptcha验证的实现示例
2021/08/23 Vue.js
中国古风插画师排行榜:夏达第一,第三是阴阳师姑获鸟皮肤创作者
2022/03/18 国漫