浅谈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.MVC的模板标签系统(一)
Sep 05 PHP
用PHP将数据导入到Foxmail的实现代码
Sep 05 PHP
PHP函数篇之掌握ord()与chr()函数应用
Dec 05 PHP
如何判断php数组的维度
Jun 10 PHP
php中使用in_array() foreach array_search() 查找数组是否包含时的性能对比
Apr 14 PHP
PHP中使用curl入门教程
Jul 02 PHP
linux平台编译安装PHP7并安装Redis扩展与Swoole扩展实例教程
Sep 30 PHP
Yii2框架BootStrap样式的深入理解
Nov 07 PHP
PHP自带方法验证邮箱、URL、IP是否合法的函数
Dec 08 PHP
PHP数据库操作三:redis用法分析
Aug 16 PHP
php策略模式简单示例分析【区别于工厂模式】
Sep 25 PHP
让whoops帮我们告别ThinkPHP6的异常页面
Mar 02 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实现的MySQL数据浏览器
2007/03/11 PHP
php自动获取目录下的模板的代码
2010/08/08 PHP
php数组去重实例及分析
2013/11/26 PHP
php简单实现无限分类树形列表的方法
2015/03/27 PHP
PHP中strncmp()函数比较两个字符串前2个字符是否相等的方法
2016/01/07 PHP
yii框架无限极分类的实现方法
2017/04/08 PHP
php使用redis的几种常见操作方式和用法示例
2020/02/20 PHP
对联广告js flash激活
2006/10/19 Javascript
Document 对象的常用方法
2009/07/31 Javascript
js 表格隔行颜色
2009/12/02 Javascript
文字溢出实现溢出的部分再放入一个新生成的div中具体代码
2013/05/17 Javascript
JS获得浏览器版本和操作系统版本的例子
2014/05/13 Javascript
AngularJS中的过滤器使用详解
2015/06/16 Javascript
jQuery实现折叠、展开的菜单组效果代码
2015/09/16 Javascript
json定义及jquery操作json的方法
2016/09/29 Javascript
Vue 全局loading组件实例详解
2018/05/29 Javascript
vue filters的使用详解
2018/06/11 Javascript
解决select2在bootstrap modal中不能正常使用的问题
2018/08/09 Javascript
JS合并两个数组的3种方法详解
2019/10/24 Javascript
javascript代码实现简易计算器
2021/01/25 Javascript
解决python写的windows服务不能启动的问题
2014/04/15 Python
Python SQLite3数据库操作类分享
2014/06/10 Python
Python实现的绘制三维双螺旋线图形功能示例
2018/06/23 Python
Python重新加载模块的实现方法
2018/10/16 Python
Python Opencv实现图像轮廓识别功能
2020/03/23 Python
python实现对图片进行旋转,放缩,裁剪的功能
2019/08/07 Python
python中class的定义及使用教程
2019/09/18 Python
墨西哥网上超市:Superama
2018/07/10 全球购物
法学函授自我鉴定
2014/02/06 职场文书
座谈会主持词
2014/03/20 职场文书
文科毕业生自荐书范文
2014/04/17 职场文书
伊索寓言教学反思
2014/05/01 职场文书
党员考试作弊检讨书1000字
2015/02/16 职场文书
如何在CocosCreator里画个炫酷的雷达图
2021/04/16 Javascript
PHP实现rar解压读取扩展包小结
2021/06/03 PHP
SQL Server数据库基本概念、组成、常用对象与约束
2022/03/20 SQL Server