Android 常用設(shè)計(jì)模式之 -- 策略模式

作者 夏至 歡迎轉(zhuǎn)載,也請(qǐng)保留這段申明
http://blog.csdn.net/u011418943/article/details/73702423

很多對(duì)設(shè)計(jì)模式不太熟悉的小伙伴看到這個(gè)模式的時(shí)候,一臉懵逼?有這個(gè)模式,我怎么沒聽過(guò),好像不怎么常用啊! 你根本不是老司機(jī) ?。?! 別急,別先脫褲子,聽我講完。

1、策略模式定義

首先先解釋下,什么叫策略模式? 通俗來(lái)講,我們希望找出應(yīng)用中可能需要變動(dòng)的地方,把它們獨(dú)立出來(lái),并封裝起來(lái),不要和那些不需要變化的代碼混在一起 ,使代碼更加有彈性和擴(kuò)展性。

何為變動(dòng),比如生活中,一件衣服的價(jià)格總是變動(dòng),比如打折優(yōu)惠什么,比如旅行的方式,你可以選擇坐車,徒步或者坐飛機(jī)等等;而再 Android 中,這種模式也是非常常見的,比如 listview 的 setadpter() ,比如只是簡(jiǎn)單處理文字,我們可以使用 arrayadapter,simpleadapter,而稍微復(fù)雜一點(diǎn)的,則是使用 baseadapter,但最終我們調(diào)用的都是 setadapter,傳進(jìn)來(lái)的 adapter 其實(shí)用的 策略模式 (Strategy).

當(dāng)然經(jīng)常用的動(dòng)畫插值器也是用的策略模式,這個(gè)就是上面說(shuō)到的變動(dòng)的地方;

2、實(shí)踐

上面說(shuō)了一些理論的,下面我們來(lái)實(shí)踐一下。有個(gè)需求,有一家商店,衣服促銷,但是打折方式有三種

  • 買一件打 9.7 折
  • 買滿 200 減 20
  • 買兩件以上打 9 折

看到這個(gè)需求,你可能是會(huì)說(shuō),這也太簡(jiǎn)單了吧,是的,我們來(lái)看看傳統(tǒng)寫法是怎么做的,首先定義一個(gè) discount 的類,easy,如下:

public class DisCount {
    public static final int USE_PRECENT = 0; //使用百分比
    public static final int USE_MOMEY = 1; //到底一定價(jià)錢返回現(xiàn)金
    public static final int USE_TWO_PRESENT = 2; //兩件打多少折
    private int strategy;
    private float percent;
    private float price;
    public DisCount(int strategy,  float price,float percent) {
        this.strategy = strategy;
        this.percent = percent;
        this.price = price;
    }
    public float getPrice(){
        switch (this.strategy){
            case USE_PRECENT:
                price = price * percent;
                break;
            case USE_MOMEY:
                price = price - 20;
                break;
            case USE_TWO_PRESENT:
                price = (price + price) * percent;
                break;
        }
        return price;
    }
}

上面的代碼中,很簡(jiǎn)單,通過(guò)一個(gè) switch 來(lái)選擇 mode ,然后計(jì)算出價(jià)錢,這里只是簡(jiǎn)單演示,就用就簡(jiǎn)單的邏輯了。然后再新建一個(gè) cashactivity 類:

public class CashActivity extends AppCompatActivity {
    private static final String TAG = "zsr";
    private float price;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DisCount disCount = null;
       disCount = new DisCount(DisCount.USE_PRECENT,120,0.97f);
        float price = disCount.getPrice();
        Log.d(TAG, "我只買了一件衣服: "+price);
        disCount = new DisCount(DisCount.USE_MOMEY,240,0);
        price = disCount.getPrice();
        Log.d(TAG, "我買了兩件衣服: "+price);
        disCount = new DisCount(DisCount.USE_TWO_PRESENT,240,0.9f);
        price = disCount.getPrice();
        Log.d(TAG, "我買了兩件衣服: "+price);
    }
}

很簡(jiǎn)單,就不解釋了,打印如下:

Paste_Image.png

很明顯,在低價(jià)格,肯定是兩件減20劃算,當(dāng)兩件很貴的時(shí)候,肯定是打折便宜,等等,我寫什么東西,明顯個(gè)鬼啊,你根本不是程序猿?。?!

3、使用策略模式

好吧,假如現(xiàn)在老板覺得這樣還不夠吸引客戶,加多兩個(gè)需求

  • 三件及以上享受 8.8 折優(yōu)惠
  • 買滿1000元以上,除了享受8.8折,還能免費(fèi)辦理至尊卡一張,并立減 100

好吧,可能真的入錯(cuò)行了,應(yīng)該當(dāng)銷售的。。。。。

這個(gè)時(shí)候,你肯定會(huì)不屑一顧,這很簡(jiǎn)單啊,加多兩個(gè) case ,把邏輯寫進(jìn)去就行了!然而,老司機(jī)的車不是那么容易搭的,假如以后每次修改一下規(guī)則,或添加多幾個(gè)優(yōu)惠什么的,也要這樣嗎?這種在小規(guī)模還好,如果需求很多,這樣弄沒被弄死真的算不錯(cuò)的了,而且這也違背了設(shè)計(jì)原則了,而且擴(kuò)展性和彈性都不好。

怎么辦? 按照上面的理解,我們應(yīng)該把這部分變化的代碼抽取出來(lái)。

根據(jù)設(shè)計(jì)原則第二條: 針對(duì)接口編程,而不是針對(duì)實(shí)現(xiàn)編程。

所以,設(shè)計(jì)一個(gè)打折的接口:

public interface IDisCount {
    float getPrice(int originPrice); //接口的函數(shù)只要一個(gè)原始價(jià)錢即可
}

想一下 listview 的 setadapter ,那么我們是不是也可以設(shè)置一個(gè) setdiscount ,只要輸入打折類型,就可以知道價(jià)格了?當(dāng)然可以,設(shè)計(jì)一個(gè)契約類,代碼如下:

public class DisCountControl  {
    private IDisCount iDisCount;
    //設(shè)置使用哪種打折方式
    public void setDisCount(IDisCount iDisCount){
        this.iDisCount = iDisCount;
    }
    //返回價(jià)格
    public float getFinalPrice(int originCash){
        return this.iDisCount.getPrice(originCash);
    }
}

那么,接下來(lái)只要在子類中,實(shí)現(xiàn) discount 的getPrice 即可了,上面有三個(gè),這里就寫三個(gè)把,如下:

單件打折:


public class DisCountPercent implements IDisCount {
    private float mPercent;
    public DisCountPercent(float mPercent) {
        this.mPercent = mPercent;
    }
    @Override
    public float getPrice(int originPrice) {
        return originPrice * this.mPercent;
    }
}

兩件減現(xiàn)金

public class CashDisCount implements IDisCount {
    private float salemomey; //需要減的價(jià)格
    public CashDisCount(float salemomey) {
        this.salemomey = salemomey;
    }
    @Override
    public float getPrice(int originPrice) {
        return originPrice - salemomey;
    }
}

** 兩件打折 **

public class MoreThanTwoClothesDisCount implements IDisCount{
    private float mPercent;
    public MoreThanTwoClothesDisCount(float mPercent) {
        this.mPercent = mPercent;
    }
    @Override
    public float getPrice(int originPrice) {
        return originPrice * this.mPercent;
    }
}

好吧,類的命名 low b 了點(diǎn),這里也是簡(jiǎn)單實(shí)現(xiàn)了邏輯,然后主函數(shù)那里:

public class CashActivity extends AppCompatActivity {
    private static final String TAG = "zsr";
    private float price;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        IDisCount disCount = null;
        DisCountControl disCountControl = new DisCountControl();
        //單價(jià)
        disCount = new DisCountPercent(0.99f);
        disCountControl.setDisCount(disCount);
        Log.d(TAG, "我只買了一件衣服: "+disCountControl.getFinalPrice(120));
        //買兩件減現(xiàn)金
        disCount = new CashDisCount(20);
        disCountControl.setDisCount(disCount);
        Log.d(TAG, "我只買了至少兩件衣服: "+disCountControl.getFinalPrice(240));
        // 買了兩件打折的
        disCount = new MoreThanTwoClothesDisCount(0.9f);
        disCountControl.setDisCount(disCount);
        Log.d(TAG, "我只買了至少兩件衣服: "+disCountControl.getFinalPrice(240));
    }
}

可以看到,我們就new 了一個(gè)方法,然后用 discountcontrol.setDisCount 的類型就實(shí)現(xiàn)了我們的功能;

相較于原始的方式,雖然多了幾個(gè)類,但是擴(kuò)展性和彈性都變得更好了,不過(guò)那也不叫多幾個(gè)類,這樣單獨(dú)出來(lái)維護(hù)起來(lái)反而更加容易一些;

學(xué)會(huì)設(shè)計(jì)模式,更加讓我們的代碼健壯性和擴(kuò)展性更好,當(dāng)然這里只是簡(jiǎn)單的拋出一個(gè)實(shí)例,更多理解,要需要在實(shí)戰(zhàn)項(xiàng)目中;

這個(gè)模式會(huì)堅(jiān)持寫下去的,盡量用簡(jiǎn)單的例子,就算是小白也能理解這些模式,喜歡的可以關(guān)注一波哦。

最后編輯于
?著作權(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)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,094評(píng)論 25 709
  • 設(shè)計(jì)模式基本原則 開放-封閉原則(OCP),是說(shuō)軟件實(shí)體(類、模塊、函數(shù)等等)應(yīng)該可以拓展,但是不可修改。開-閉原...
    西山薄涼閱讀 4,081評(píng)論 3 14
  • 動(dòng)物世界里,兩只高角羚羊,為爭(zhēng)奪領(lǐng)地和交配權(quán),猛烈地戰(zhàn)斗起來(lái),它倆想分出勝負(fù),因此打得不可開交??上С隽藗€(gè)大問題:...
    MacQingfeng閱讀 585評(píng)論 0 0
  • 很不巧,窗外晴朗得連暗淡的星都看得清清楚楚,它們?cè)谄岷诘纳n穹中顯得很密、很多、很亮、很美。 仿佛所有的光都...
    晴時(shí)霧閱讀 266評(píng)論 1 1

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