浅谈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上传图片、删除图片实现代码
May 12 PHP
php判断上传的Excel文件中是否有图片及PHPExcel库认识
Jan 11 PHP
php小经验:解析preg_match与preg_match_all 函数
Jun 29 PHP
php实现的Captcha验证码类实例
Sep 22 PHP
PHP中的output_buffering详细介绍
Sep 27 PHP
推荐5款跨平台的PHP编辑器
Dec 25 PHP
laravel安装zend opcache加速器教程
Mar 02 PHP
PHP判断是否为空的几个函数对比
Apr 21 PHP
php基于Fleaphp框架实现cvs数据导入MySQL的方法
Feb 23 PHP
Yii框架表单模型和验证用法
May 20 PHP
功能强大的php文件上传类
Aug 29 PHP
使用git迁移Laravel项目至新开发环境的步骤详解
Apr 06 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
在yii中新增一个用户验证的方法详解
2013/06/20 PHP
PHP实现批量修改文件后缀名的方法
2015/07/30 PHP
php多进程模拟并发事务产生的问题小结
2018/12/07 PHP
laravel框架中表单请求类型和CSRF防护实例分析
2019/11/23 PHP
js 加载并解析XML字符串的代码
2009/12/13 Javascript
基于promise.js实现nodejs的promises库
2014/07/06 NodeJs
js使用for循环及if语句判断多个一样的name
2014/09/09 Javascript
Javascript中的默认参数详解
2014/10/22 Javascript
jQuery 获取屏幕高度、宽度的简单实现案例
2016/05/17 Javascript
快速获取/设置iframe内对象元素的几种js实现方法
2016/05/20 Javascript
javascript类型系统_正则表达式RegExp类型详解
2016/06/24 Javascript
ES6正则表达式的一些新功能总结
2017/05/09 Javascript
深入理解vue中的$set
2017/06/01 Javascript
JS 验证密码 不能为空,必须含有数字、字母、特殊字符,长度在8-12位
2017/06/21 Javascript
vue+webpack实现异步加载三种用法示例详解
2018/04/24 Javascript
Angular学习教程之RouterLink花式跳转
2018/05/03 Javascript
详解基于vue-cli3.0如何构建功能完善的前端架子
2018/10/09 Javascript
Python 模块EasyGui详细介绍
2017/02/19 Python
详解Python列表赋值复制深拷贝及5种浅拷贝
2019/05/15 Python
Pandas DataFrame数据的更改、插入新增的列和行的方法
2019/06/25 Python
如何用OpenCV -python3实现视频物体追踪
2019/12/04 Python
Python实现清理微信僵尸粉功能示例【基于itchat模块】
2020/05/29 Python
Python实现迪杰斯特拉算法过程解析
2020/09/18 Python
python获取命令行参数实例方法讲解
2020/11/02 Python
高清屏中使用Canvas绘图出现模糊的问题及解决方法
2019/06/03 HTML / CSS
新百伦折扣店:Joe’s New Balance Outlet
2016/08/20 全球购物
Oasis服装官网:时尚女装在线
2020/07/09 全球购物
巴西最大的运动品牌:Olympikus
2020/07/14 全球购物
什么是典型的软件三层结构?软件设计为什么要分层?软件分层有什么好处?
2012/03/14 面试题
Java的基础面试题附答案
2016/01/10 面试题
大学生毕业自荐信
2013/10/10 职场文书
会展策划与管理专业大学生职业生涯规划
2014/02/07 职场文书
理财投资建议书
2014/03/12 职场文书
云冈石窟导游词
2015/02/04 职场文书
三十年同学聚会致辞
2015/07/28 职场文书
2019年个人工作总结范文
2019/03/25 职场文书