登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

zczhangchi 的博客

学习笔记

 
 
 

日志

 
 

PHP与魔兽--看PHP设计模式 03 完(转)  

2009-10-30 11:53:12|  分类: php资料 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

三、工厂模式:

问题的提出:最初在设计模式一书中,许多设计模式都鼓励使用松散耦合。要理解这个概念,让我们最好谈一下许多开发人员从事大型系统的艰苦历程。在更改一个代码片段时,就会发生问题,系统其他部分——您曾认为完全不相关的部分中也有可能出现级联破坏。该问题在于紧密耦合。系统某个部分中的函数和类严重依赖于系统的其他部分中函数和类的行为和结构。您需要一组模式,使这些类能够相互通信,但不希望将它们紧密绑定在一起,以避免出现联锁。在大型系统中,许多代码依赖于少数几个关键类。需要更改这些类时,可能会出现困难。例如,假设您有一个从文件读取的User类。您希望将其更改为从数据库读取的其他类,但是,所有的代码都引用从文件读取的原始类。这时候,使用工厂模式会很方便。工厂模式是一种类,它具有为您创建对象的某些方法。您可以使用工厂类创建对象,而不直接使用new。这样,如果您想要更改所创建的对象类型,只需更改该工厂即可。使用该工厂的所有代码会自动更改。

问题的解决:呵呵,估计有些phper没看懂吧,没关系,那是我从其他地方抄的,我们下面还是通过魔兽来进行吧。这一部分,我看都已经有前人写好了,我就基本上照抄了,请前人不要见怪啊。呵呵。前面选了暗夜精灵族(Nighy Elf),和兽族(ORC),因为小精灵(Wisp)能建造建筑,还能自爆。所以根据这个我们下面先写个小精灵(Wisp)的类。

Php代码
  1. < ?php   
  2. class Wisp {   
  3.     private $mHealthPoint = 120; //这是小精灵的血量   
  4.     private $mArmor = 0; //这是小精灵的护甲   
  5.     //小精灵能建造建筑   
  6.     public    function Build() {   
  7.         echo '精灵建造建筑咯。<br/>';   
  8.      }   
  9.   
  10.     //每个小精灵被造出来时还会占用一个人口   
  11.     public    function __construct() {   
  12.         echo '你已经建造了一个小精灵。<br/>';   
  13.         //这里是增加已有人口的代码   
  14.      }   
  15.   
  16.     //每个小精灵死亡会减少你占用的人口   
  17.     public    function __destruct() {   
  18.         //这里是减少已有人口的代码   
  19.      }   
  20. }   
  21. ?>  
< ?php class Wisp {    private $mHealthPoint = 120; //这是小精灵的血量    private $mArmor = 0; //这是小精灵的护甲    //小精灵能建造建筑    public    function Build() {        echo '精灵建造建筑咯。<br/>';    }    //每个小精灵被造出来时还会占用一个人口    public    function __construct() {        echo '你已经建造了一个小精灵。<br/>';        //这里是增加已有人口的代码    }    //每个小精灵死亡会减少你占用的人口    public    function __destruct() {        //这里是减少已有人口的代码    }}?>

把这些代码放在Arms / Wisp.php中。啊,还有还有,还有苦工(Peon)的类

Php代码
  1. < ?php   
  2. class Peon {   
  3.     private $mHealthPoint = 250; //这是苦工的血量   
  4.     private $mArmor = 0; //这是苦工的护甲   
  5.     //苦工能建造建筑   
  6.     public    function Build() {   
  7.         echo '苦工建造建筑咯。<br/>';   
  8.      }   
  9.   
  10.     //每个苦工被造出来时还会占用一个人口   
  11.     public    function __construct() {   
  12.         echo '你已经建造了一个苦工。<br/>';   
  13.         //这里是增加已有人口的代码   
  14.      }   
  15.   
  16.     //每个苦工死亡会减少你占用的人口   
  17.     public    function __destruct() {   
  18.   
  19.         //这里是减少已有人口的代码   
  20.      }   
  21. }   
  22. ?>  
< ?php class Peon {    private $mHealthPoint = 250; //这是苦工的血量    private $mArmor = 0; //这是苦工的护甲    //苦工能建造建筑    public    function Build() {        echo '苦工建造建筑咯。<br/>';    }    //每个苦工被造出来时还会占用一个人口    public    function __construct() {        echo '你已经建造了一个苦工。<br/>';        //这里是增加已有人口的代码    }    //每个苦工死亡会减少你占用的人口    public    function __destruct() {        //这里是减少已有人口的代码    }}?>

把这些代码放在Arms / Peon.php中。等等,这样岂不是很复杂,魔兽里面还有那么多的兵种,另外都还有两个种族,每次创建一个兵就要new一个,要是记不住这个兵的类名,岂不是new不了?而且如果一个兵是一个类,放在一个文件里,那是不是一开始就要把所有的几十上百个文件都include一次啊,那效率可想而知啊。嘿嘿,当然是有解决办法的啊,我们再写一个类把这些类都封装起来,这个把兵种都封装起来的类我们称之为工厂类,他可以像生产产品一样,来创建兵,帮我们对其实例化。下面我们就来看这个类怎么实现吧。

Php代码
  1. < ?php   
  2. class CreatArms {   
  3.     public    function __construct() {}   
  4.   
  5.     public    function Creat($arms, $path = '') {   
  6.         include $path.$arms.'.php'; //包含要这个类的文件   
  7.         return new $arms; //返回你创建的兵种对象的句柄   
  8.      }   
  9. }   
  10. ?>  
< ?php class CreatArms {    public    function __construct() {}    public    function Creat($arms, $path = '') {        include $path.$arms.'.php'; //包含要这个类的文件        return new $arms; //返回你创建的兵种对象的句柄    }}?>

这样,即使在兵种多样的情况下,我们仍然可以很方便地实例化:$creator = new CreatArms();

$w1 = $creator - >Creat('兵种名', '前缀或路径');

例如创建小精灵:$creator = new CreatArms(); //不管创建啥,我都只要使用这个类

$w1 = $creator - >Creat(‘Wisp’, ’. / Arms / ’); //创建一个小精灵

$w1 - >Build(); //让小精灵造建筑

这就是传说中的工厂模式,通过工厂模式,对于如论坛那种有很多种用户的,特别是为了以后扩展比较方便的,采用工厂模式,是个很好的解决方法。在zend framework中的Zend_Form、Zend_Filter、Zend_Validate就是用工厂模式来构架的。

四、观察者模式:

问题的提出:观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单:一个对象通过添加一个方法(该方法允许另一个对象,即观察者注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。

问题的解决:呵呵,上面还是抄的,看不懂没关系,我们今天重点是玩魔兽。已经造了很长时间的兵了,现在可以出去带兵打仗了,如果我去打电脑的兽族,那么电脑与那个兽族同盟的精灵族就会过来帮忙。那么如何让他知道自己的同盟受攻击了呢。现在我们就来讨论这个问题。首先我们写一下结盟的抽象类:

Php代码
  1. < ?php   
  2. abstract class abstractAlly {   
  3.     //放置观察者的集合,这里以简单的数组来直观演示   
  4.     protected $oberserverCollection;   
  5.     //增加观察者的方法,参数为观察者(也是玩家)   
  6.     public    function addOberserver($oberserver) {   
  7.         $this - >oberserverCollection[] = new oberserver($oberserver);   
  8.      }   
  9.   
  10.     //将被攻击的电脑的名字通知各个观察者   
  11.     public    function notify($beAttackedPlayerName) {   
  12.         //把观察者的集合循环   
  13.         foreach($this - >oberserverCollection as $oberserver) {   
  14.             //调用各个观察者的救援函数,参数为被攻击的电脑的名字,if用来排除被攻击的电脑的观察者   
  15.             if ($oberserver - >name != $beAttackedPlayerName) $oberserver - >help($beAttackedPlayerName);   
  16.          }   
  17.      }   
  18.   
  19.     abstract public    function beAttacked($beAttackedPlayer);   
  20. }   
  21. ?>  
< ?php abstract 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 beAttacked($beAttackedPlayer);}?>

下面我们就写具体的结盟类:

Php代码
  1. < ?php   
  2. class Ally extends abstractAlly {   
  3.     //构造函数,将所有电脑玩家的名称的数组作为参数   
  4.     public  
  5.     function __construct($allPlayer) {   
  6.         //把所有电脑玩家的数组循环   
  7.         foreach($allPlayer as $player) {   
  8.             //增加观察者,参数为各个电脑玩家的名称   
  9.             $this - >addOberserver($player);   
  10.          }   
  11.      }   
  12.   
  13.     //将被攻击的电脑的名字通知各个观察者   
  14.     public    function beAttacked($beAttackedPlayerName) {   
  15.         //调用各个观察者的救援函数,参数为被攻击的电脑的名字,if用来排除被攻击的电脑的观察者   
  16.         $this - >notify($beAttackedPlayerName);   
  17.      }   
  18. }   
  19. ?>  
< ?php class Ally extends abstractAlly {    //构造函数,将所有电脑玩家的名称的数组作为参数    public    function __construct($allPlayer) {        //把所有电脑玩家的数组循环        foreach($allPlayer as $player) {            //增加观察者,参数为各个电脑玩家的名称            $this - >addOberserver($player);        }    }    //将被攻击的电脑的名字通知各个观察者    public    function beAttacked($beAttackedPlayerName) {        //调用各个观察者的救援函数,参数为被攻击的电脑的名字,if用来排除被攻击的电脑的观察者        $this - >notify($beAttackedPlayerName);    }}?>

接着在二、策略模式中我们定义的player类中加入一个help方法

Php代码
  1. public help($beAttackedPlayerName) {   
  2.     //这里简单的输出,谁去救谁,最后加一个换行,便于显示   
  3.     echo $this - >name." help ".$beAttackedPlayerName."<br />";   
  4. }  
public help($beAttackedPlayerName) {    //这里简单的输出,谁去救谁,最后加一个换行,便于显示    echo $this - >name." help ".$beAttackedPlayerName."<br />";}

这样就行了。最后就是仿真了。

Php代码
  1. < ?php   
  2. //先设置敌方电脑   
  3. $allComputePlayer = array('NighyElf2', 'ORC2');   
  4. //新建电脑结盟   
  5. $Ally = new Ally($allComputePlayer);   
  6. //假设我进攻了电脑的兽族   
  7. $Ally - >beAttacked('ORC2');   
  8. ?>  
< ?php//先设置敌方电脑$allComputePlayer = array('NighyElf2', 'ORC2');//新建电脑结盟$Ally = new Ally($allComputePlayer);//假设我进攻了电脑的兽族$Ally - >beAttacked('ORC2');?>

这样结盟的另一家就能接到通知,去救援。观察者模式主要就是用在这种情况下。可以将某个状态变化立即通知到相关的对象,相关的对象就可以采用相应的策略。例如,zend framework中的Zend_Message就是用的观察者模式。好了,今天就玩到这里,以后有空再和大家一起玩魔兽啊。

  评论这张
 
阅读(121)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018