版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、使市场前段时间看到有人用魔兽来解释设计模式,感觉很有意思,于是我把它改了改,又添加了些设计模式内容,今天发出来。有些地方借鉴了前人的内容,没有注明,请前人不要见怪啊。这里用大家感兴趣的魔兽3来讨论PHP的几种常见的设计模式:单件模式、策略模式、工厂模式、观察者模式。今天就讲这四个吧,以后继续。这些设计模式,都是针对面向对象来说的,所以都用PHP5,另外在这里我想说的是PHP4从2008年8月8日(我记得是和北京奥运会同一天,没查证,呵呵)的时候官方就发了最后一个PHP4的补丁,这意味这PHP4的时代已经终结,所以,我建议大家现在就别理PHP4吧,就以PHP5来说吧。一、单件模式:问题的提出:某
2、些应用程序资源是独占的,因为有且只有一个此类型的资源。例如,通过数据库句柄到数据库的连接是独占的。您希望在应用程序中共享数据库句柄,因为在保持连接打开或关闭时,它是一种开销,在获取单个页面的过程中更是如此。问题的解决:那么下面我们就开始玩魔兽吧。首先双击war3.exe,这时候就开始运行魔兽了。我们用代码来实现吧。<?phpclass War3 public function _construct()echo "War3 is Running.","<br />"$war = new War3();运行!很好,输出War3 is Run
3、ning.我们已经可以开始游戏了,但是,如果我在代码末尾再加入$war2 = new War3();$war3 = new War3();会怎么样呢?我们试试,输出结果:War3 is Running.War3 is Running.War3 is Running.完了,如果不小心双击了两次就开了3个魔兽,那如果再双击几次,那电脑肯定爆掉。我们还是来想想解决方法吧。既然我们不能这么随意的就把这个类实例化了,那么我们就把构造函数改成私有方法。class War3 private function _construct()echo "War3 is Running.",&quo
4、t;<br />"可是私有变量外部是无法访问的,这样以来,我们就连一个都打不开了啊。别急,我们再给他加一个不用通过实例化,外部也能访问的函数,那就是静态函数,class War3 private function _construct()echo "War3 is Running.","<br />" public static function runWar() 通过这个静态的方法runWar()我们来控制类War3的实例化,那么还缺上一个标识,我们再创建一个标识,通过这个标识来表示我们的类是否已经实例化,如果实例化,
5、直接返回句柄就行了。把类修改成class War3 protected static $_instance = null;private function _construct()echo "War3 is Running.","<br />" public static function runWar()if (null = self:$_instance) self:$_instance = new self();return self:$_instance;当然,我们运行魔兽时的实例化也要换种方法,就通过$war = War3:runW
6、ar();就能开始玩魔兽了,好了,下面把完整的代码附上来:<?phpclass War3 protected static $_instance = null;private function _construct()echo "War3 is Running.","<br />"public static function runWar()if (null = self:$_instance) self:$_instance = new self();return self:$_instance;$war = War3:runWar(
7、);$war2 = War3:runWar();$war3 = War3:runWar();运行一下,结果是:War3 is Running.太好了,我双击了这么多次,也就只运行了一个魔兽,现在随便你怎么打开,机子都不会爆掉了。这就是传说中的单价模式,主要用于一些很占资源的而且实例仅有一个实例就够用的东西,比如,zend framework中的Zend_Controller_Front前端控制器,就是采用单价模式来设计的,大家有兴趣的话可以看看那个。二、策略模式:问题的提出:在此模式中,算法是从复杂类提取的,因而可以方便地替换。例如,如果要更改搜索引擎中排列页的方法,则策略模式是一个不错的选择
8、。思考一下搜索引擎的几个部分 一部分遍历页面,一部分对每页排列,另一部分基于排列的结果排序。在复杂的示例中,这些部分都在同一个类中。通过使用策略模式,您可将排列部分放入另一个类中,以便更改页排列的方式,而不影响搜索引擎的其余代码。问题的解决:呵呵,不讲那么复杂,刚才魔兽好不容易打开了,我们还是玩魔兽好了。下面我们选battle,哇好多种族啊,有人族(Human),兽族(ORC),暗夜精灵族(Nighy Elf),不死族(Undead)。我选精灵族(Nighy Elf),再选一个精灵族和两个兽族(ORC),一个兽族和我是一家的,另一个精灵族和兽族是另一家的。每一个玩家在进入游戏后都会得到一些资源
9、,如一个大厅,五个小精灵(苦工)和一个矿山。这些可以称为是初始化的一些东西,这里我们就可以用到策略模式来封装这些初始化。进入正题,首先我们来构建一个玩家类:<?phpclass player/玩家名字protected $_name;/种族protected $_race;/队伍protected $army;/建筑protected $building;/人口protected $population;/黄金protected $gold;/木材protected $wood;/构造函数,设定所属种族public function _construct($race)$this->
10、race = $race;/_get()方法用来获取保护属性private function _get($property_name)if(isset($this->$property_name) return($this->$property_name);else return(NULL);/_set()方法用来设置保护属性private function_set($property_name,$value)$this->$property_name=$value;接着,我们再建一个玩家初始化的接口,<?phpinterface initialPlayer/制造初始化
11、的部队public function giveArmy($player);/制造初始化的建筑public function giveBuilding($player);/初始化资源public function giveSource($player);好了,到这里我们就该对这个接口来实现了,为了方便,我只选了两个种族,就只写这两个种族的初始化了:首先是精灵族:<?phpclass NighyElfInitial implements initialPlayer/制造初始化的部队public function giveArmy($player)/五个小精灵for($i=0; $i<=
12、5;$i+)$creator = new CreatArms();/这个是创建部队类,在后面得工厂模式中会用到,这里我就不多说了$player->army = $creator->Creat('Wisp','./Arms/');/制造初始化的建筑public function giveBuilding($player)$creator = new CreatBuildings();/一个基地$player->building = $creator->Creat('TownHall','./Buildings/
13、9;);/一个矿场$player->building = $creator->Creat('Mine','./Buildings/');/初始化人口上限public function giveSource($player)$player->population= 10;$player->gold= 1000;$player->wood= 100;接下来是兽族:<?phpclass ORCInitial implements initialPlayer/制造初始化的部队public function giveArmy($play
14、er)/五个苦工for($i=0; $i<=5;$i+)$creator = new CreatArms();/这个是创建部队类,在后面得工厂模式中会用到,这里我就不多说了$player->army = $creator->Creat('Peon','./Arms/');/制造初始化的建筑public function giveBuilding($player)$creator = new CreatBuildings();/一个基地$player->building = $creator->Creat('TownHall&
15、#39;,'./Buildings/');/一个矿场$player->building = $creator->Creat('Mine','./Buildings/');/初始化人口上限public fu nction giveSource($player)$player->population= 10;$player->gold= 1000;$player->wood= 100;好了,到这里初始化代码就写好了,现在还差一个控制这些初始化得类,也就是封装他们:<?phpclass initialControll
16、er /构造函数,参数为玩家的数组public function _construct($playerArray)foreach ($playerArray as $player)switch ($player->race)case 'NighyElf':$initialController = new NighyElfInitial();break;case 'ORC':$initialController = new ORCInitial();break;$initialController->giveArmy($player);$initial
17、Controller->giveBuilding($player);$initialController->giveSupply($player);最后就是简单这么一调用,就OK:<?php/有两个精灵族两个兽族$playerArray = array(new player('NighyElf'), new player('NighyElf'), new player('ORC'), new player('ORC');/进行初始化工作$initialController = new initialControl
18、ler($playerArray);这就是策略模式,他将不同情况下的算法封装在一起。Zend framework中的Zend_Application_Resource就是用策略模式来设计的。三、工厂模式:问题的提出:最初在设计模式一书中,许多设计模式都鼓励使用松散耦合。要理解这个概念,让我们最好谈一下许多开发人员从事大型系统的艰苦历程。在更改一个代码片段时,就会发生问题,系统其他部分 您曾认为完全不相关的部分中也有可能出现级联破坏。该问题在于紧密耦合。系统某个部分中的函数和类严重依赖于系统的其他部分中函数和类的行为和结构。您需要一组模式,使这些类能够相互通信,但不希望将它们紧密绑定在一起,以避
19、免出现联锁。在大型系统中,许多代码依赖于少数几个关键类。需要更改这些类时,可能会出现困难。例如,假设您有一个从文件读取的 User 类。您希望将其更改为从数据库读取的其他类,但是,所有的代码都引用从文件读取的原始类。这时候,使用工厂模式会很方便。工厂模式是一种类,它具有为您创建对象的某些方法。您可以使用工厂类创建对象,而不直接使用 new。这样,如果您想要更改所创建的对象类型,只需更改该工厂即可。使用该工厂的所有代码会自动更改。问题的解决:呵呵,估计有些phper没看懂吧,没关系,那是我从其他地方抄的,我们下面还是通过魔兽来进行吧。这一部分,我看都已经有前人写好了,我就基本上照抄了,请前人不要
20、见怪啊。呵呵。前面选了暗夜精灵族(Nighy Elf),和兽族(ORC),因为小精灵(Wisp)能建造建筑,还能自爆。所以根据这个我们下面先写个小精灵(Wisp)的类。<?phpclass Wispprivate $mHealthPoint = 120;/这是小精灵的血量private $mArmor = 0;/这是小精灵的护甲/小精灵能建造建筑public function Build()echo '精灵建造建筑咯。<br/>'/每个小精灵被造出来时还会占用一个人口public function _construct()echo '你已经建造了一个小
21、精灵。<br/>'/这里是增加已有人口的代码/每个小精灵死亡会减少你占用的人口public function _destruct()/这里是减少已有人口的代码把这些代码放在Arms/ Wisp.php中。啊,还有还有,还有苦工(Peon)的类<?phpclass Peonprivate $mHealthPoint = 250;/这是苦工的血量private $mArmor = 0;/这是苦工的护甲 /苦工能建造建筑public function Build()echo '苦工建造建筑咯。<br/>' /每个苦工被造出来时还会占用一个人口pu
22、blic function _construct()echo '你已经建造了一个苦工。<br/>'/这里是增加已有人口的代码/每个苦工死亡会减少你占用的人口public function _destruct()/这里是减少已有人口的代码把这些代码放在Arms/ Peon.php中。等等,这样岂不是很复杂,魔兽里面还有那么多的兵种,另外都还有两个种族,每次创建一个兵就要new一个,要是记不住这个兵的类名,岂不是new不了?而且如果一个兵是一个类,放在一个文件里,那是不是一开始就要把所有的几十上百个文件都include一次啊,那效率可想而知啊。嘿嘿,当然是有解决办法的啊
23、,我们再写一个类把这些类都封装起来,这个把兵种都封装起来的类我们称之为工厂类,他可以像生产产品一样,来创建兵,帮我们对其实例化。下面我们就来看这个类怎么实现吧。<?phpclass CreatArmspublic function _construct()public function Creat($arms,$path = '')include $path.$arms.'.php' /包含要这个类的文件return new $arms; /返回你创建的兵种对象的句柄这样,即使在兵种多样的情况下,我们仍然可以很方便地实例化:$creator = new C
24、reatArms();$w1 = $creator->Creat('兵种名','前缀或路径');例如创建小精灵:$creator = new CreatArms();/不管创建啥,我都只要使用这个类$w1 = $creator->Creat(Wisp,./Arms/);/创建一个小精灵$w1->Build();/让小精灵造建筑这就是传说中的工厂模式,通过工厂模式,对于如论坛那种有很多种用户的,特别是为了以后扩展比较方便的,采用工厂模式,是个很好的解决方法。在zend framework中的Zend_Form、Zend_Filter、Zend_V
25、alidate就是用工厂模式来构架的。四、观察者模式:问题的提出:观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单:一个对象通过添加一个方法(该方法允许另一个对象,即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。问题的解决:呵呵,上面还是抄的,看不懂没关系,我们今天重点是玩魔兽。已经造了很长时间的兵了,现在可以出去带兵打仗了,如果我去打电脑的兽族,那么电脑与那个兽族同盟的精灵族就会过来帮忙。那么如何让他知道自己的同盟受攻击了呢。现在我们就来讨
26、论这个问题。首先我们写一下结盟的抽象类:<?phpabstract class abstractAlly/放置观察者的集合,这里以简单的数组来直观演示protected $oberserverCollection;/增加观察者的方法,参数为观察者(也是玩家)public function addOberserver($oberserver)$this->oberserverCollection = new oberserver($oberserver);/将被攻击的电脑的名字通知各个观察者public function notify($beAttackedPlayerName)/把观察者的集合循环foreach ($this->oberserverCollection as $oberserver)/调用各个观察者的救援函数,参数为被攻击的电脑的名字,if用来排除被攻击的电脑的观察者if($oberserver->name != $beAttackedPlayerName)$oberserver->help($beAttackedPlayerName); abstract public function
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五年度农民工工资拖欠专项整改协议3篇
- 减肥方法及其效果研究综述
- 二零二五年度房产代持保密协议范本3篇
- 新生儿心肺复苏知识
- 临床引起双硫仑样反应特点、诊断标准、分度、鉴别诊断及处理要点
- 二零二五年度信息安全管理责任承诺(含应急预案)2篇
- 二零二五年度his系统与药品供应链系统对接合同
- 河南省商丘市(2024年-2025年小学六年级语文)统编版质量测试(上学期)试卷及答案
- 黑龙江大庆市(2024年-2025年小学六年级语文)部编版能力评测((上下)学期)试卷及答案
- 贵州商学院《概率论与随机过程》2023-2024学年第一学期期末试卷
- 2022年中国农业银行(广东分行)校园招聘笔试试题及答案解析
- 品牌管理第五章品牌体验课件
- 基于CAN通讯的储能变流器并机方案及应用分析报告-培训课件
- 外科医师手术技能评分标准
- 保姆级别CDH安装运维手册
- 菌草技术及产业化应用课件
- GB∕T 14527-2021 复合阻尼隔振器和复合阻尼器
- 隧道二衬、仰拱施工方案
- 颤病(帕金森病)中医护理常规
- 果胶项目商业计划书(模板范本)
- 旋挖钻成孔掏渣筒沉渣处理施工工艺
评论
0/150
提交评论