浅谈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 array_push 数组函数
Dec 26 PHP
php 连接mysql连接被重置的解决方法
Feb 15 PHP
深入理解PHP几个算法:PHP冒泡、PHP二分法、PHP求素数、PHP乘法表
Jun 06 PHP
php字符串替换函数substr_replace()用法实例
Mar 17 PHP
php实现Mongodb自定义方式生成自增ID的方法
Mar 23 PHP
PHP中的一些常用函数收集
May 26 PHP
PHP正则验证Email的方法
Jun 15 PHP
PHP实现简单ajax Loading加载功能示例
Dec 28 PHP
PHP实现支持CURL字符串证书传输的方法
Mar 23 PHP
Smarty模板类内部原理实例分析
Jul 03 PHP
php 根据URL下载远程图片、压缩包、pdf等文件到本地
Jul 26 PHP
ThinkPHP5+UEditor图片上传到阿里云对象存储OSS功能示例
Aug 05 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中foreach()用法汇总
2015/07/02 PHP
使用PHP生成二维码的方法汇总
2015/07/22 PHP
php通过淘宝API查询IP地址归属等信息
2015/12/25 PHP
php json相关函数用法示例
2017/03/28 PHP
php使用flock阻塞写入文件和非阻塞写入文件的实例讲解
2017/07/10 PHP
PHP结合Redis+MySQL实现冷热数据交换应用案例详解
2019/07/09 PHP
javascript编程起步(第六课)
2007/02/27 Javascript
如何简单地用YUI做JavaScript动画
2007/03/10 Javascript
Jquery中getJSON在asp.net中的使用说明
2011/03/10 Javascript
javascript复制粘贴与clipboardData的使用
2014/10/16 Javascript
JavaScript实现点击按钮字体放大、缩小
2016/02/29 Javascript
BootStrap日期控件在模态框中选择时间下拉菜单无效的原因及解决办法(火狐下不能点击)
2016/08/18 Javascript
微信小程序开发之大转盘 仿天猫超市抽奖实例
2016/12/08 Javascript
原生JS实现图片轮播效果
2016/12/26 Javascript
微信小程序的动画效果详解
2017/01/18 Javascript
jQuery中table数据的值拷贝和拆分
2017/03/19 Javascript
利用vue.js把静态json绑定bootstrap的table方法
2018/08/28 Javascript
bootstrap自定义样式之bootstrap实现侧边导航栏功能
2018/09/10 Javascript
深入了解JavaScript 防抖和节流
2019/09/12 Javascript
vue 保留两位小数 不能直接用toFixed(2) 的解决
2020/08/07 Javascript
跟老齐学Python之网站的结构
2014/10/24 Python
Python中生成器和yield语句的用法详解
2015/04/17 Python
python实现数据图表
2017/07/29 Python
基于TensorFlow常量、序列以及随机值生成实例
2020/01/04 Python
python脚本和网页有何区别
2020/07/02 Python
老生常谈CSS中的长度单位
2016/06/27 HTML / CSS
Tom Dixon官网:英国照明及家具设计和制造公司
2019/03/01 全球购物
英国拖鞋购买网站:Bedroom Athletics
2020/02/28 全球购物
CAT鞋加拿大官网:CAT Footwear加拿大
2020/08/05 全球购物
管理学专业个人求职信范文
2013/12/13 职场文书
网络技术专业求职信
2014/02/18 职场文书
医学生职业生涯规划书范文
2014/03/13 职场文书
婚庆司仪开场白
2015/05/29 职场文书
如何利用Matlab制作一款真正的拼图小游戏
2021/05/11 Python
python tqdm用法及实例详解
2021/06/16 Python
Spring Boot实战解决高并发数据入库之 Redis 缓存+MySQL 批量入库问题
2022/02/12 Redis