浅谈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 相关文章推荐
3.从实例开始
Oct 09 PHP
一个简单的PHP投票程序源码
Mar 11 PHP
SESSION信息保存在哪个文件目录下以及能够用来保存什么类型的数据
Jun 17 PHP
php命令行使用方法和命令行参数说明
Apr 08 PHP
php利用事务处理转账问题
Apr 22 PHP
PHP随手笔记整理之PHP脚本和JAVA连接mysql数据库
Nov 25 PHP
PHP常见的6个错误提示及解决方法
Jul 07 PHP
php 修改上传文件大小限制实例详解
Oct 23 PHP
Yii 2.0自带的验证码使用经验分享
Jun 19 PHP
php 中htmlentities导致中文无法查询问题
Sep 10 PHP
YII框架页面缓存操作示例
Apr 29 PHP
PHP接入支付宝接口失效流程详解
Nov 10 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
Yii2框架中使用PHPExcel导出Excel文件的示例
2017/08/09 PHP
解决laravel查询构造器中的别名问题
2019/10/17 PHP
PHP SESSION跨页面传递失败解决方案
2020/12/11 PHP
面向对象的Javascript之二(接口实现介绍)
2012/01/27 Javascript
邮箱下拉自动填充选择示例代码附图
2014/04/03 Javascript
JS实现鼠标经过好友列表中的好友头像时显示资料卡的效果
2014/07/02 Javascript
javascript中undefined与null的区别
2015/08/16 Javascript
JS实现的论坛Ajax打分效果完整实例
2015/10/31 Javascript
BootStrap 智能表单实战系列(五) 表单依赖插件处理
2016/06/13 Javascript
微信小程序 picker-view 组件详解及简单实例
2017/01/10 Javascript
canvas绘制七巧板
2017/02/03 Javascript
详解如何使用vue-cli脚手架搭建Vue.js项目
2017/05/19 Javascript
基于Cookie常用操作以及属性介绍
2017/09/07 Javascript
React如何将组件渲染到指定DOM节点详解
2017/09/08 Javascript
jQuery+vue.js实现的多选下拉列表功能示例
2019/01/15 jQuery
详解NodeJs项目 CentOs linux服务器线上部署
2019/09/16 NodeJs
基于NodeJS开发钉钉回调接口实现AES-CBC加解密
2020/08/20 NodeJs
[06:07]刀塔密之二:攻之吾命受之吾幸
2014/07/03 DOTA
[01:33]真香警告!DOTA2勇士令状不朽珍藏Ⅱ饰品欣赏
2018/06/26 DOTA
python使用pil生成图片验证码的方法
2015/05/08 Python
分析并输出Python代码依赖的库的实现代码
2015/08/09 Python
举例讲解Python中字典的合并值相加与异或对比
2016/06/04 Python
Python中模块string.py详解
2017/03/12 Python
python 接口返回的json字符串实例
2018/03/27 Python
使用Python制作简单的小程序IP查看器功能
2019/04/16 Python
Python Pandas 如何shuffle(打乱)数据
2019/07/30 Python
flask框架json数据的拿取和返回操作示例
2019/11/28 Python
香蕉共和国加拿大官网:Banana Republic加拿大
2018/08/06 全球购物
意大利珠宝店:Luxury Zone
2019/01/05 全球购物
C#怎么让一个窗口居中显示?
2015/10/20 面试题
日语专业毕业生自荐信
2013/11/11 职场文书
大学自主招生自荐信
2013/12/16 职场文书
创业计划书——互联网商机
2014/01/12 职场文书
优秀民警事迹材料
2014/01/29 职场文书
民警个人对照检查剖析材料
2014/09/17 职场文书
python 算法题——快乐数的多种解法
2021/05/27 Python