iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 3
0
自我挑戰組

初探設計模式系列 第 3

[ Day 3 ] 初探設計模式 - 策略模式 (Strategy Pattern)

前言


今天介紹一下策略模式,
稍微結合一下昨天介紹的簡單的工廠模式,
實現一些簡單的小工具,
這兩天有發現有一些基礎沒介紹到,
會找機會把基礎的思想補完一下。

策略模式

定義一系列的演算法,並且把這些算法,
用介面封裝到有公共介面的策略類中,使他們可以互相替換。

策略模式用策略的介面來替換在某個實體ˋ中的方法
可以經由替換不同的策略使得物件擁有不同的行為
經過策略的組合,我們得以獲得行為不同的物件。

優點:

  • 靈活的替換不同的行為(演算法)
  • 策略拓展容易
  • 避免使用很多if else

缺點:

  • 必須自行決定要使用哪種策略
  • 可能產生很多策略類

或許可以將這些行為不同的物件用工廠模式封裝起來,解決使用這些模式時需要先事先知道有哪些策略,並且需要自行決定使用哪些策略的問題。

UML

 Strategy Pattern

試著用程式碼實現 - 1

假設我們要實現一個計算機的話...

先定義一個介面,用這個介面定義一系列演算法。

public interface IStrategy {
    public int caculate(int a , int b);
}

將加減乘除等一系列的算法實現出來

public class add implements IStrategy {
    @Override
    public int caculate(int a, int b) {
        return a + b;
    }
}

public class minus implements IStrategy {
    @Override
    public int caculate(int a, int b) {
        return a - b ;
    }
}

public class multyply implements IStrategy {
    @Override
    public int caculate(int a, int b) {
        return a * b;
    }
}

public class divide implements IStrategy {
    @Override
    public int caculate(int a, int b) {
        return a / b ;
    }
}

用一個類裝這個算法,並且用昨天講到簡單的工廠模式封裝一下

public class Calculator {

    private int now = 0 ;

    private IStrategy strategy ;

//    策略模式
    public int execute(int a , int b){
        return strategy.caculate(a,b);
    }

    public void reset(){
        this.now = 0 ;
    }

//    簡單工廠模式
    public void setStrategy(DoType doType) {
        switch (doType){
            case ADD:
                this.strategy = new add();
                break;
            case MINUS:
               this.strategy = new minus();
                break;
            case DIVIDE:
                this.strategy = new divide();
                break;
            case MULTYPLY:
               this.strategy = new multyply();
                break;
        }
    }

    enum DoType{
        ADD , MINUS , DIVIDE , MULTYPLY
    }

}

實現了一個簡單的計算機,

當然只有加減乘除的計算機的演算法不太複雜,

但是現在如果要加入一個次方的演算法,

我們也能很簡單的實現它。

因為還有一些時間我們試著再實現一種

試著用程式碼實現 - 2

假設我們現在需要一個根據里程數幫忙計價的計算機

public interface IStrategy {
    public int calculate();
}

Bus & MRT 的里程計價方式

public class BusStrategy implements IStrategy {
    @Override
    public int calculate(int km) {

//        一段票15元
//        十公里內一段票,超過十公里兩段票

        int count = 0 ;

        if( km <= 10 ){
            count = 1 ;
        }else if( km > 10){
            count = 2 ;
        }

        return count * 15 ;

    }
}

public class MRTStrategy implements IStrategy {
    @Override
    public int calculate(int km) {

//        小於十公里20元,超過每五公里多五元

        int result = 0 ;

        if(km <= 0) return  result ;

        if(km <= 10) {
            result = 20 ;
        }

        if(km > 10){
            int count = (int)Math.ceil((((double)km - 10) / 5));
            result = 20 + 5 * count ;
        }

        return result;

    }
}

依據里程數計價的計算機,

只要選定你的移動方式(在這裡是MRT or Bus),

就可以根據移動方式來計算出需要的費用。

public class PriceCalculator {
    IStrategy strategy;

    private PriceCalculator(){};

    public PriceCalculator(IStrategy strategy){
        this.strategy = strategy;
    }

    public void setStrategy(IStrategy strategy) {
        this.strategy = strategy;
    }

    public int calculate(int km){
        return this.calculate(km,strategy);
    }

    public int calculate(int km , IStrategy strategy){
        this.strategy = strategy;
        return strategy.calculate(km);
    }
}

今天的文章就先到這邊啦~
範例有兩個,但是都很簡單的!
大家有心也一定能夠掌握,
我們雖然不比別人聰明,甚至起步比別人慢,
但是只要有根性氣勢
相信這種恆毅力才是真正的寶藏,
明天再繼續加油~

如果有什麼問題或錯誤的地方,歡迎留言或來信喔~


上一篇
[ Day 2 ] 初探設計模式 - 工廠方法模式 (Factory Method Pattern)
下一篇
[ Day 4 ]初探設計模式 - 關於那些更基本的事情...系統架構(System Architecture)
系列文
初探設計模式30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
pratbrid
iT邦新手 5 級 ‧ 2022-01-25 17:31:45

(手殘亂按剛打好的被刪掉了...簡單描述
先感謝邦友的文章!

MRTStrategy 有兩處錯誤

  1. 內文寫十公里,code是20公里
  2. 假設 25 km,結果是 10 元
public class MRTStrategy implements IStrategy {
    @Override
    public int calculate(int km) {

//        小於十公里20元,超過每五公里五元

        int result = 0 ;

        if(km <= 0) return  result ;

        if(km <= 20) {
            result = 20 ;
        }

        if(km > 20){
            int count = (( km - 20 ) / 5 ) + 1 ;
            result = result + 5 * count ;
        }

        return result;

    }
}
Daniel Wu iT邦新手 4 級 ‧ 2022-01-26 00:31:31 檢舉

已改正,感謝糾錯!!

1
leochang658
iT邦新手 5 級 ‧ 2023-09-07 21:56:00

小於十公里20元,超過每五公里多五元

依照這句話,15公里應該是25(=20+5)元,但是依照程式碼卻是30(= 20+5 * (((15-10)/5)+ 1))元,請問是我哪裡誤會了嗎?

Daniel Wu iT邦新手 4 級 ‧ 2023-09-08 13:39:25 檢舉

看來我當時都在亂寫 XDDD

int count = (( km - 20 ) / 5 ) + 1 ;

我的猜測是這邊的 +1 想要達成的是未滿五公里以五公里計算,如果是這樣的話,我的建議如下

int count = (int)Math.ceil((((double)km - 10) / 5));
Daniel Wu iT邦新手 4 級 ‧ 2023-09-11 11:18:08 檢舉

好呀,就採用你的 看起來沒有什麼錯誤

我要留言

立即登入留言