PHP、鸭子

Joe上班公司做了一套相当成功的模拟鸭子游戏:SimUDuck。游戏中有各种鸭子,边游泳戏水,边呱呱叫(注意是“呱呱叫”)。显然Joe使用了OO技术,设计了鸭子的基类。由于每个鸭子的长相不同所以Display()方法是抽象的,Duck类也是抽象类

 1 abstract class duck{
2 //游泳
3 public function swim(){
4 echo "I can swim<br/>";
5 }
6 //呱呱叫
7 public function quack(){
8 echo "I can quack<br/>";
9 }
10 //外观
11 abstract public function display();
12 }

 

 1     //红色的鸭子
2 class redduck extends duck{
3 public function display(){
4 echo "I,m red<br/>";
5 }
6 }
7 //黄色的鸭子
8 class yellowduck extends duck{
9 public function display(){
10 echo "I,m yellow<br/>";
11 }
12 }


但是,最近公司为了开了头脑风暴会议,要更新产品,并决定通过让鸭子会飞来击败竞争者。这时Joe应该怎么办呢?

 

毕竟Joe是个OO程序员,这个对他来说一周不到就可以搞定了。他的做法是在Duck类中加上fly()方法,这样不是所有的鸭子都会继承fly()了嘛~~^_^(注意:Joe认为所有的鸭子都会飞,而且飞起来都是一样的,所以就只要在基类中实现fly()方法就行了……)

 

但是可怕的发生了……

 

在股东会议的展示上,很多的“橡皮鸭子”飞了起来,看来Joe要去求职网站(Monster.com)去逛逛了……原来Joe忽略了:并非所有的鸭子都会飞。在基类中加上的方法将使得那些不适合该行为的派生类也具有了这种行为。

 

 1 abstract class duck{
2 //
3 public function fly(){
4 echo "I can fly<br/>";     
      }
5 //游泳
6 public function swim(){
7 echo "I can swim<br/>";
8 }
9 //呱呱叫
10 public function quack(){
11 echo "I can quack<br/>";
12 }
13 //外观
14 abstract public function display();
15 }

 

Joe心里想,不就是橡皮鸭子不会飞嘛,那我在橡皮鸭子类(RubberDuck)里重写一个fly()方法,这个方法什么也不做不就行了,而且橡皮鸭子不会呱呱叫,但是会吱吱叫,那就在RubberDuck类里覆盖quack()方法,写成吱吱叫不就行了~~^_^。(但是,如果以后再引入了诱饵鸭怎么办,只能再覆盖fly()quack()方法呗~~)。

 

看来Joe认识到了继承可能不是解决这个问题的答案了,因为他刚刚接到通知,希望以后每六个月就更新产品一次,这样每当有新的鸭子类出现他就要去覆盖,真是一个噩梦!!

 

利用接口如何??

 

Joe说:“我可以把fly()方法从超类中取出来,放进一个”Flyable“的接口中。这么一来只有会飞的鸭子才实现这个接口,当然也可可以用来设计一个”Quackable”的接口啊~”。

 

这个时候,小秘又偷偷打电话给Joe说:“这真是一个超笨的主意!!这么一来重复的代码更多了,如果你认为覆盖几个方法是差劲,那么对于一个有48Duck子类都要稍微修改一下飞行的行为,你该怎么说?!!“。

 

我们知道,并不是所有的派生类都具有飞行和呱呱叫的行为,所以继承不是适当的解决方案。虽然上面的接口FlyableQuackable可以解决“一部分“问题,但是造成了代码不能复用,这只能算是从一个噩梦跳到另一个噩梦。甚至在会飞的鸭子中,飞行的动作的不一样~~

 

我们的第一个设计原则的想法是,把会变化的部分取出并且“封装”起来,好让其他部分不会收到影响。这样使得代码变化不经意的后果变少系统更有弹性。

 

换句话说,每次来新的需求,就会使某方面的代码发生变化,那么我们就可以确定,这部分的代码需要被抽出来,跟其他的代码有所区分。

 

这种原则的另一种思考方式:“把会变化的部分取出来并且封装起来,以便以后可以轻易的改动或者扩充这一部分,而不影响不需要变化的其他部分”。

 

使系统重的某部分改变不会影响其他部分!!

 

目前,除了fly()quack()的问题之外,Duck类还算一切正常。为了分开“变化和不变化的部分”,准备建立两组类(完全远离Duck类),一个是fly相关的,一个是quack相关的。每组实现各自的动作。也就要把flyquack行为从Duck类中分离出来,建立一组新的类。

 1 //飞动作接口
2 interface Flybehavior{
3 public function fly();
4 }
5 //各种具体实现
6 class canfly implements Flybehavior{
7   public function fly(){
8   echo "wa wa fly<br>";
9 }
10 }
11 class unfly implements Flybehavior{
12   public function fly(){
13   echo "can't fly<br>";
14 }
15 }


 

 

 

 

 

下面就要讨论如何去实现飞行和呱呱叫的行为的类。

 

我们希望一切能有弹性。例如,我们想要产生一个新的绿头鸭实例,并且指定特定“类型”的飞行行为给它。我们目的是让鸭子的行为可以动态改变(运行时可以改变,例如橡胶鸭子不能飞,给它加个助燃器就能像火箭一样)。

 

我们第二个设计原则的思想是,鸭子的行为将被放在分开的类中,此类专门提供某行为接口的实现。这样鸭子就不需要知道行为的实现细节了。

 

abstract class duck{
public function setfly($name){
return new $name;
}
//游泳
public function swim(){
echo "I can swim<br/>";
}
//呱呱叫
public function quack(){
echo "I can quack<br/>";
}
//外观
abstract public function display();
}

 

1 $duck=new yellowduck();
2 $duck->setfly($_GET['flymethod']?$_GET['flymethod']:'unfly')->fly();
3 $duck->display();
4 $duck->swim();
5 $duck->quack();




 


 

posted @ 2011-10-28 13:47  struts-2.1.6-all.zip  阅读(321)  评论(0)    收藏  举报