策略模式

設計模式一書中引用了商場促銷的例子來講解策略模式.現在我們就來看看代碼

1.0版本

class ViewController: UIViewController {
    var total:Double = 0.0 // 總計
    var price:Double = 50 // 單價
    var num:Double = 3 // 數量

    override func viewDidLoad() {
        super.viewDidLoad()
        let totalPrices = price * num
        total = total + totalPrices
        print("總價為:", total)
        // 總價為:150
    }
}

加入打折操作

class ViewController: UIViewController {
    var total:Double = 0.0       // 總計
    var price:Double = 50        // 單價
    var num:Double = 3           // 數量
    var payMod = "正常收費"       // 收費模式

    override func viewDidLoad() {
        super.viewDidLoad()
        var totalPrices:Double = 0
        switch payMod {
        case "正常收費":
            totalPrices = price * num
        case "8折":
            totalPrices = price * num * 0.8
        case "75折":
            totalPrices = price * num * 0.75
        case "5折":
            totalPrices = price * num * 0.5
        default:
            break
        }
        total = total + totalPrices
        print("單價:",price,"個數:",num, "收費模式:",payMod,"合計:", total)
        // 單價:50 個數:3 收費模式:正常收費 總價為:150
    }
}

再來看看使用簡單工廠模式的寫法

class CashSuper: NSObject {
    //現金父類
    func acceptCash(money:Double)->Double{
        return money
    }
}
class CashNormal: CashSuper {
    // 正常收費子類
    override func acceptCash(money: Double) -> Double {
        return money
    }
}

class CashRebate: CashSuper {
    // 打折收費子類
    private var moneyRebate:Double = 1.0
    // 初始化方法
    init(moneyRebate:Double) {
        self.moneyRebate = moneyRebate
    }
    override func acceptCash(money: Double) -> Double {
        return money * moneyRebate
    }
}

class CashReturn: CashSuper {
    // 返利收費子類
    private var moneyCondition:Double = 0.0
    private var moneyReturn:Double = 0.0
    
    // 初始化方法
    init(moneyCondition:Double, moneyReturn:Double) {
        self.moneyCondition = moneyCondition
        self.moneyReturn = moneyReturn
    }
    
    override func acceptCash(money: Double) -> Double {
        var result = money
        if money >= moneyCondition {
            result = money - floor(money / moneyCondition) * moneyReturn
        }
        return result
    }
class CashFactory {
    //工廠類
    static func createCashAccept(type:String)->CashSuper {
        var cs: CashSuper?
        switch type {
        case "正常收費":
            cs = CashNormal()
        case "滿300返100":
            cs = CashReturn(moneyCondition: 300, moneyReturn: 100)
        case "打8折":
            cs = CashRebate(moneyRebate: 0.8)
        default:
            break
        }
        return cs!
    }
}
class ViewController: UIViewController {
    // 客戶端代碼
    var total:Double = 0.0 // 總計
    var price:Double = 50 // 單價
    var num:Double = 3 // 數量
    var payMod = "正常收費"

    override func viewDidLoad() {
        super.viewDidLoad()
        let csuper = CashFactory.createCashAccept(payMod)
        var totalPrices:Double = 0
        // 傳入商品總價
        totalPrices = csuper.acceptCash(price * num)
        total = total + totalPrices
        print("單價:",price,"個數:",num, "收費模式:",payMod,"合計:", total)
        // 單價:50 個數:3 收費模式:正常收費 總價為:150
    }
}

如果我們使用策略模式寫的話會是什么樣子?

策略模式只需要在增加一個context類
class CashContext: NSObject {
    private var cs:CashSuper
    init(csuper:CashSuper) {
        self.cs = csuper
    }
    func getResult(money:Double)->Double{
        return cs.acceptCash(money)
    }
}

客戶端代碼

class ViewController: UIViewController {
    var total:Double = 0.0 // 總計
    var price:Double = 50 // 單價
    var num:Double = 3 // 數量
    var payMod = "正常收費"

    override func viewDidLoad() {
        super.viewDidLoad()
        var cc: CashContext?
        switch payMod {
        case "正常收費":
            cc = CashContext(csuper: CashNormal())
        case "滿300返100":
            cc = CashContext(csuper: CashReturn(moneyCondition: 300, moneyReturn: 100))
        case "打8折":
            cc = CashContext(csuper: CashRebate(moneyRebate: 0.8))
        default:
            break
        }
        var totalPrices:Double = 0
        totalPrices = cc!.getResult(price * num)
        total = total + totalPrices
        print("單價:",price,"個數:",num, "收費模式:",payMod,"合計:", total)
        // 單價:50 個數:3 收費模式:正常收費 總價為:150
    }
}

使用策略模式的話,進行判斷的語句又回到了客戶端代碼中,這肯定不是我們想要的結果那么將策略模式和簡單工廠模式結合一下

再來看看策略模式和簡單工廠模式的結合版

需要修改cashContext類

class CashContext: NSObject {
    private var cs:CashSuper?
    init(type:String) {
        switch type {
        case "正常收費":
            cs = CashNormal()
        case "滿300返100":
            cs = CashReturn(moneyCondition: 300, moneyReturn: 100)
        case "打8折":
            cs = CashRebate(moneyRebate: 0.8)
        default:
            break
        }
    }
    
    func getResult(money:Double)->Double{
        return cs!.acceptCash(money)
    }
}

客戶端代碼修改

class ViewController: UIViewController {
    var total:Double = 0.0 // 總計
    var price:Double = 50 // 單價
    var num:Double = 3 // 數量
    var payMod = "正常收費"

    override func viewDidLoad() {
        super.viewDidLoad()
        var csuper: CashContext?
        csuper = CashContext(type: payMod)
        var totalPrices:Double = 0
        totalPrices = csuper!.getResult(price * num)
        total = total + totalPrices
        print("單價:",price,"個數:",num, "收費模式:",payMod,"合計:", total)
        // 單價:50 個數:3 收費模式:正常收費 總價為:150
    }
}

策略模式就是封裝算法的,但在實踐中,我們發現可以用它來封裝幾乎任何類型的規則, 只要在分析過程中聽到需要在不同時間應用不同的業務規則,就可以考慮使用策略模式處理這種變化的可能性
但是在基本的策略模式中, 選擇所用的具體實現職責還是由客戶端對象在承擔,并轉給策略模式的Context對象.這本身并沒有接觸客戶端需要選擇判斷的壓力,而策略模式與簡單工廠模式節后和,選擇具體時間的職責也可以由Context來承擔,這就最大化減輕了客戶端的職責.
但是書中還提到這不是最優的解決辦法.讓我們繼續之后的學習吧~

@旺仔牛奶
2016年3月29日

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容