4)策略模式

模擬鴨子游戲的應(yīng)用程序,要求:游戲中會出現(xiàn)各種顏色外形的鴨子记焊,一邊游泳戲水,一邊呱呱叫栓撞。

方法一:運用繼承的特性遍膜,將其中共同的部分提升出來,避免重復(fù)編程腐缤。

即:設(shè)計一個鴨子的超類(Superclass),并讓各種鴨子繼承這個超類捌归。

public class Duck{
     public void quack(){  //呱呱叫
              System.out.println("呱呱叫");
      }
     public void swim(){   //游泳
            System.out.println(" 游泳");
      }    
     public  abstratact void display(); /*因為外觀不一樣,讓子類自己去決定了岭粤。*/
}

對于它的子類只需簡單的繼承就可以了惜索,并實現(xiàn)自己的display()方法。

//野鴨
 public class MallardDuck extends Duck{
     public void display(){
          System.out.println("野鴨的顏色...");
   }
 }
//紅頭鴨
 public class RedheadDuck extends Duck{
     public void display(){
          System.out.println("紅頭鴨的顏色...");
   }
}

不幸的是剃浇,現(xiàn)在客戶又提出了新的需求巾兆,想讓鴨子飛起來。這個對于我們OO程序員虎囚,在簡單不過了角塑,在超類中在加一個方法就可以了。

public class Duck{
     public void quack(){  //呱呱叫
              System.out.println("呱呱叫");
      }
     public void swim(){   //游泳
            System.out.println(" 游泳");
    }    
    public  abstract void display(); /*因為外觀不一樣淘讥,讓子類自己去決定了圃伶。*/
   public void fly(){
        System.out.println("飛吧!鴨子"); 
  }
}

對于不能飛的鴨子蒲列,在子類中只需簡單的覆蓋窒朋。

//殘廢鴨
 public class DisabledDuck extends Duck{
     public void display(){
          System.out.println("殘廢鴨的顏色...");
   }
   public void fly(){
    //覆蓋,變成什么事都不做蝗岖。 
  }
} 

其它會飛的鴨子不用覆蓋侥猩。
這樣所有的繼承這個超類的鴨子都會fly了。但是問題又出來了抵赢,客戶又提出有的鴨子會飛欺劳,有的不能飛唧取。

點評:

對于上面的設(shè)計,你可能發(fā)現(xiàn)一些弊端划提,如果超類有新的特性枫弟,子類都必須變動,這是我們開發(fā)最不喜歡看到的腔剂,一個類變讓另一個類也跟著變媒区,這有點不符合OO設(shè)計了。這樣很顯然的耦合了一起掸犬。利用繼承-->耦合度太高了袜漩。

方法二:用接口改進

我們把容易引起變化的部分提取出來并封裝之,來應(yīng)付以后的變法湾碎。雖然代碼量加大了宙攻,但可用性提高了,耦合度也降低了介褥。
我們把Duck中的fly方法和quack提取出來座掘。

    public interface Flyable{
      public void fly(); 
  }
   public interface Quackable{
     public void quack();
  }

最后Duck的設(shè)計成為:

public class Duck{
     public void swim(){   //游泳
            System.out.println(" 游泳");
    }    
    public  abstract void display(); /*因為外觀不一樣,讓子類自 己去決定了柔滔。*/
}

而MallardDuck,RedheadDuck,DisabledDuck 就可以寫成為:

//野鴨
 public class MallardDuck extends Duck  implements Flyable,Quackable{
     public void display(){
          System.out.println("野鴨的顏色...");
   }
   public void fly(){
    //實現(xiàn)該方法
  }
   public void quack(){
    //實現(xiàn)該方法
  }
 }
//紅頭鴨
 public class RedheadDuck extends Duck implements Flyable,Quackable{
     public void display(){
          System.out.println("紅頭鴨的顏色...");
   }
   public void fly(){
    //實現(xiàn)該方法
  }
   public void quack(){
    //實現(xiàn)該方法
  }
} 
//殘廢鴨 只實現(xiàn)Quackable(能叫不能飛)
 public class DisabledDuck extends Duck implements Quackable{
     public void display(){
          System.out.println("殘廢鴨的顏色...");
   }
   public void quack(){
    //實現(xiàn)該方法
  }
}

點評:

好處:這樣已設(shè)計溢陪,我們的程序就降低了它們之間的耦合咱圆。

不足:Flyable和 Quackable接口一開始似乎還挺不錯的糠悼,解決了問題(只有會飛到鴨子才實現(xiàn) Flyable),但是Java接口不具有實現(xiàn)代碼贞奋,所以實現(xiàn)接口無法達到代碼的復(fù)用超全。

方法三:策略模式

對上面各方式的總結(jié):

繼承的好處:讓共同部分,可以復(fù)用.避免重復(fù)編程.

繼承的不好:耦合性高.一旦超類添加一個新方法,子類都繼承,擁有此方法,若子類相當部分不實現(xiàn)此方法,則要進行大批量修改.繼承時,子類就不可繼承其它類了.

接口的好處:解決了繼承耦合性高的問題.且可讓實現(xiàn)類,繼承或?qū)崿F(xiàn)其它類或接口.

接口的不好:不能真正實現(xiàn)代碼的復(fù)用.可用以下的策略模式來解決.

我們有一個設(shè)計原則:
找出應(yīng)用中相同之處咆霜,且不容易發(fā)生變化的東西,把它們抽取到抽象類中嘶朱,讓子類去繼承它們蛾坯;
找出應(yīng)用中可能需要變化之處,把它們獨立出來疏遏,不要和那些不需要變化的代碼混在一起脉课。
現(xiàn)在,為了要分開“變化和不變化的部分”财异,我們準備建立兩組類(完全遠離Duck類)倘零,一個是"fly"相關(guān)的,另一個是“quack”相關(guān)的宝当,每一組類將實現(xiàn)各自的動作。比方說胆萧,我們可能有一個類實現(xiàn)“呱呱叫”庆揩,另一個類實現(xiàn)“吱吱叫”俐东,還有一個類實現(xiàn)“安靜”。

首先寫兩個接口订晌。FlyBehavior(飛行行為)和QuackBehavior(叫的行為).

 public interface FlyBehavior{
     public void fly();     
 }
 public interface QuackBehavior{
     public void quack();
 }

我們在定義一些針對FlyBehavior的具體實現(xiàn)虏辫。

 public class FlyWithWings implements FlyBehavior{
    public void  fly(){
     //實現(xiàn)了所有有翅膀的鴨子飛行行為。
   }
 }
public class FlyNoWay implements FlyBehavior{
 
    public void  fly(){
      //什么都不做锈拨,不會飛
    }
 }   

針對QuackBehavior的幾種具體實現(xiàn)砌庄。

public class Quack implements QuackBehavior{
    public void quack(){
      //實現(xiàn)呱呱叫的鴨子
  }
}
 
public class Squeak implements QuackBehavior{
    public void quack(){
      //實現(xiàn)吱吱叫的鴨子 
  }
}
 
public class MuteQuack implements QuackBehavior{
    public void quack(){
      //什么都不做,不會叫
  }
}

點評一:

這樣的設(shè)計奕枢,可以讓飛行和呱呱叫的動作被其他的對象復(fù)用娄昆,因為這些行為已經(jīng)與鴨子類無關(guān)了。而我們增加一些新的行為缝彬,不會影響到既有的行為類萌焰,也不會影響“使用”到飛行行為的鴨子類。

最后我們看看Duck 如何設(shè)計谷浅。

 public class Duck{        //在抽象類中,聲明各接口,定義各接口對應(yīng)的方法.
      FlyBehavior flyBehavior;//接口
      QuackBehavior quackBehavior;//接口
       public Duck(){}
       public abstract void display();
       public void swim(){
        //實現(xiàn)游泳的行為
        }
       public void performFly(){
            flyBehavior.fly();  //由于是接口,會根據(jù)繼承類實現(xiàn)的方式,而調(diào)用相應(yīng)的方法.
     }
     public void performQuack(){
          quackBehavior.quack();();
    }
}

看看MallardDuck如何實現(xiàn)扒俯。

//通過構(gòu)造方法,生成'飛','叫'具體實現(xiàn)類的實例,從而指定'飛','叫'的具體屬性
 public class MallardDuck extends Duck{
       public MallardDuck {       
        flyBehavior = new FlyWithWings ();
        quackBehavior = new Quack(); 
      //因為MallardDuck 繼承了Duck,所有具有flyBehavior 與quackBehavior 實例變量}
    public void display(){
     //實現(xiàn)
   }
 }

這樣就滿足了即可以飛一疯,又可以叫撼玄,同時展現(xiàn)自己的顏色了。
這樣的設(shè)計我們可以看到是把flyBehavior 墩邀,quackBehavior 的實例化寫在子類了掌猛。我們還可以動態(tài)的來決定。 我們只需在Duck中加上兩個方法磕蒲。

在構(gòu)造方法中對屬性進行賦值與用屬性的setter的區(qū)別:
構(gòu)造方法中對屬性進行賦值:固定留潦,不可變;
用屬性的setter辣往,可以在實例化對象后兔院,動態(tài)的變化,比較靈活站削。

  public class Duck{
      FlyBehavior flyBehavior;//接口
      QuackBehavior quackBehavior;//接口
      public void setFlyBehavior(FlyBehavior flyBehavior){
            this.flyBehavior = flyBehavior;
     }
    public void setQuackBehavior(QuackBehavior quackBehavior  {
            this.quackBehavior= quackBehavior;
     }
 }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坊萝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子许起,更是在濱河造成了極大的恐慌十偶,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件园细,死亡現(xiàn)場離奇詭異惦积,居然都是意外死亡,警方通過查閱死者的電腦和手機猛频,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門狮崩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛛勉,“玉大人,你說我怎么就攤上這事睦柴》塘瑁” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵坦敌,是天一觀的道長侣诵。 經(jīng)常有香客問我,道長狱窘,這世上最難降的妖魔是什么杜顺? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮训柴,結(jié)果婚禮上哑舒,老公的妹妹穿的比我還像新娘。我一直安慰自己幻馁,他們只是感情好洗鸵,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著仗嗦,像睡著了一般膘滨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上稀拐,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天火邓,我揣著相機與錄音,去河邊找鬼德撬。 笑死铲咨,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蜓洪。 我是一名探鬼主播纤勒,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼隆檀!你這毒婦竟也來了摇天?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤恐仑,失蹤者是張志新(化名)和其女友劉穎泉坐,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裳仆,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡腕让,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了歧斟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纯丸。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡司训,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出液南,到底是詐尸還是另有隱情,我是刑警寧澤勾徽,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布滑凉,位于F島的核電站,受9級特大地震影響喘帚,放射性物質(zhì)發(fā)生泄漏畅姊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一吹由、第九天 我趴在偏房一處隱蔽的房頂上張望若未。 院中可真熱鬧,春花似錦倾鲫、人聲如沸粗合。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隙疚。三九已至,卻和暖如春磕道,著一層夾襖步出監(jiān)牢的瞬間供屉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工溺蕉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伶丐,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓疯特,卻偏偏與公主長得像哗魂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子辙芍,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 設(shè)計模式基本原則 開放-封閉原則(OCP)啡彬,是說軟件實體(類、模塊故硅、函數(shù)等等)應(yīng)該可以拓展庶灿,但是不可修改。開-閉原...
    西山薄涼閱讀 3,761評論 3 14
  • 設(shè)計模式匯總 一吃衅、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用往踢、多...
    MinoyJet閱讀 3,922評論 1 15
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,744評論 25 707
  • 切換到新的分支進行開發(fā) 案例進行 添加路由image.png 添加刪除動作image.png 在視圖頁面添加刪除歷...
    suhuanzhen閱讀 882評論 0 0
  • 一個本就平庸的人峻呕,溫柔便是拖泥帶水利职,細致便是婆婆媽媽。
    季書青閱讀 176評論 18 1