淺談設(shè)計(jì)模式1——策略模式


已經(jīng)想看設(shè)計(jì)模式好久,但是人生就像用兩個(gè)灶眼的爐臺(tái)做酒席,小炒總是優(yōu)先于燉老湯,最后小炒都結(jié)束,開飯了,盼了一年的老湯也沒燉成。但是,今天一定要開始燉老湯。所以上午一猛勁,看完了head first的第一張——策略模式。

進(jìn)入主題
說設(shè)計(jì)模式,我覺得還是先從理論高度闡述一下,然后再娓娓道來比較合適。

1、背景敘述
還是想舉書中鴨子的示例,畢竟還是比較生動(dòng)形象。因?yàn)轼喿佑泄餐奶卣鳎喿佑蓄伾梢燥w、叫。所以定義一個(gè)屬性和兩個(gè)方法:

class Duck
{
        Color color;
        public void fly()  {println("I can fly"); }
        public void quack() { println("I can quack");}
}

鴨子又有不同的類別,比如家養(yǎng)的鴨子,野鴨。所以可以將上面的類作為基類,家養(yǎng)鴨和野鴨作為派生類。
但是,問題出現(xiàn)了,大黃鴨不會(huì)飛,可以叫。全聚德烤鴨不會(huì)飛,也不會(huì)叫。怎么辦。

方法一:使用覆蓋(override),在子類中對(duì)基類的方法進(jìn)行修改。即對(duì)于不會(huì)飛的鴨子,在子類中重寫fly()為如下函數(shù)。quack()函數(shù)同理。

public void fly(){  ;}

不好:對(duì)于fly()還好說,但是某個(gè)動(dòng)作變化比較多就會(huì)比較麻煩。比如“烹調(diào)”這個(gè)動(dòng)作,光中餐里就有:煎、炒、煮、蒸、燉、烤、焗、燒。而炒里面又有爆炒、小火慢炒等等。那么每次設(shè)計(jì)一個(gè)類,都要重新寫一遍代碼,豈不太費(fèi)事?況且還有的可以生著吃,根本不用烹調(diào)。

方法二:采用接口形式,將方法從基類中剝離出來,放到接口中,若子類需要有某個(gè)方法,就實(shí)現(xiàn)對(duì)應(yīng)接口即可。比如:

interface Fly
{
      public void fly();
}
class WildDuck implements Fly
{
    public void fly()
    {
        println("I can fly");
    }
}
class  RoastDuck 
{
      //其他代碼,不適用Fly接口
}

不好:類比較少還行,但是類多了,而且這些類要是都實(shí)現(xiàn)同一個(gè)操作,那就凄慘了。比如餃子、包子、饅頭、花卷都可以蒸熟,那這幾個(gè)類中“烹調(diào)”操作全都要重復(fù)實(shí)現(xiàn)一遍“蒸”這個(gè)操作,豈不累死。

2、策略模式
那我們?cè)撛趺崔k?將方法和屬性進(jìn)行剝離,但還不能徹底剝離(接口就是徹底剝離),徹底剝離就體現(xiàn)不出面向?qū)ο蟮奶卣?,面向過程編程就是數(shù)據(jù)和操作的完全剝離。那么我們?cè)撛趺崔k?先來看看我們需要什么:
1)統(tǒng)一的接口。也就是說,所有鴨子(不管活的死的,生的熟的),都有統(tǒng)一的接口:fly()和quack(),因?yàn)檫@個(gè)是一只鴨子該有的必備技能。
2)不同的表現(xiàn)形式。雖然每只鴨子"應(yīng)該"有這樣的技能,但是依然要“因鴨而異”。也就是說,調(diào)用不同鴨子的fly()和quack()應(yīng)該執(zhí)行不同的動(dòng)作。
由上面的兩點(diǎn),自然而然想到了“多態(tài)”。
但是,“多態(tài)”好像只有“類的多態(tài)”,沒有方法的多態(tài)。其實(shí)“多態(tài)”就是根據(jù)方法的,因?yàn)轭愋偷牟煌哉宫F(xiàn)出不同的功能。
所以,從上面的分析來看,我們就應(yīng)該把fly()和quack()兩個(gè)方法封裝到類中,然后用Duck基類來調(diào)用裝有fly()和quack()的類對(duì)象。為了不成為話嘮,我覺得直接上代碼是個(gè)不錯(cuò)選擇。

interface FlyBehave
{
      public void fly();
}
class ReallyFly implements  FlyBehave
{
      public void fly(){  println("I can fly");}
}
class CantFly implements FlyBehave
{
      public void fly(){   println("i cant fly") ;}
}
class Duck
{
      Color  color;
      FlyBehave flybehave;//注意此處,采用接口定義屬性,為了實(shí)現(xiàn)多態(tài)
      
      public Duck(FlyBehave f){ flybehave = f;}
      public void fly() {  flybehave.fly();//多態(tài)調(diào)用  }
}

//測(cè)試一下
public class Test
{
      Duck  WildDuck=new Duck(new ReallyFly());
      WildDuck.fly();//打印顯示:I can fly
}

至此,策略模式闡述完畢。總結(jié)一下特點(diǎn):
(1)基類提供統(tǒng)一接口
(2)將基類的方法封裝到其屬性中,并用接口聲明屬性,實(shí)現(xiàn)方法的多態(tài)調(diào)用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容