浅谈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 相关文章推荐
PHP4实际应用经验篇(1)
Oct 09 PHP
smtp邮件发送一例
Oct 09 PHP
别人整理的服务器变量:$_SERVER
Oct 20 PHP
介绍php设计模式中的工厂模式
Jun 12 PHP
PHP中全局变量global和$GLOBALS[]的区别分析
Aug 06 PHP
一个经典的PHP文件上传类分享
Nov 18 PHP
php使用google地图应用实例
Dec 31 PHP
老生常谈PHP面向对象之注册表模式
May 26 PHP
php根据地址获取百度地图经纬度的实例方法
Sep 03 PHP
php和html的区别点详细总结
Sep 24 PHP
PHP中类与对象功能、用法实例解读
Mar 27 PHP
Laravel 框架基于自带的用户系统实现登录注册及错误处理功能分析
Apr 14 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 simple_html_dom.php+正则 采集文章代码
2009/12/24 PHP
PHP 数组基础知识小结
2010/08/20 PHP
PHP提示Notice: Undefined variable的解决办法
2012/11/24 PHP
php metaphone()函数及php localeconv() 函数实例解析
2016/05/15 PHP
php观察者模式应用场景实例详解
2017/02/03 PHP
PHP simplexml_load_string()函数实例讲解
2019/02/03 PHP
js 走马灯简单实例
2013/11/21 Javascript
Jquery 返回json数据在IE浏览器中提示下载的问题
2014/05/18 Javascript
JavaScript中的Web worker多线程API研究
2014/12/06 Javascript
jQuery实现切换字体大小的方法
2015/03/10 Javascript
详解AngularJS如何实现跨域请求
2016/08/22 Javascript
javascript表单控件实例讲解
2016/09/13 Javascript
angularjs 中$apply,$digest,$watch详解
2016/10/13 Javascript
基于JS快速实现导航下拉菜单动画效果附源码下载
2016/10/27 Javascript
教你一步步用jQyery实现轮播器
2016/12/18 Javascript
JavaScript 中 apply 、call 的详解
2017/03/21 Javascript
Vue+Element实现表格编辑、删除、以及新增行的最优方法
2019/05/28 Javascript
微信小程序实现点击效果
2019/06/21 Javascript
Windows下的Jupyter Notebook 安装与自定义启动(图文详解)
2018/02/21 Python
python dataframe常见操作方法:实现取行、列、切片、统计特征值
2018/06/09 Python
Appium+python自动化之连接模拟器并启动淘宝APP(超详解)
2019/06/17 Python
Python实现socket非阻塞通讯功能示例
2019/11/06 Python
python 求定积分和不定积分示例
2019/11/20 Python
python读取ini配置的类封装代码实例
2020/01/08 Python
Tensorflow使用Anaconda、pycharm安装记录
2020/07/29 Python
用Python 执行cmd命令
2020/12/18 Python
css3和jquery实现的可折叠导航菜单适合放在手机网页的导航菜单
2014/09/02 HTML / CSS
求职信内容考虑哪几点
2013/10/05 职场文书
期末考试动员演讲稿
2014/01/10 职场文书
见习期自我鉴定范文
2014/03/19 职场文书
2014乡镇干部对照检查材料思想汇报
2014/09/26 职场文书
公司庆典欢迎词
2015/01/26 职场文书
上课迟到检讨书
2015/05/06 职场文书
公司职员入党自传书
2015/06/26 职场文书
MySQL的全局锁和表级锁的具体使用
2021/08/23 MySQL
vue3使用vuedraggable实现拖拽功能
2022/04/06 Vue.js