2016年2月26日 星期五

策略模式 Strategy Pattern

在轉蛋活動進行中的第2天,我還是一如往常的跟正妹聊MSN
突然PM又敲我MSN了... 

PM: 小奇,轉蛋活動賺翻拉,玩家都沒點數拉...
我: 是喔!
PM: 我想趁虛而入,阿~說錯是趁勝追擊
PM: 我想辦這個禮拜儲值點數到平台,多回饋20%點數
PM: 恩~算了!~還是買1000元送100點好了
PM: 哀阿~真的很難抉擇...我先想想好了你就先寫程式好了
我: 0.0...

我心中想了一會兒,這PM好像很善變,好像會有很多種折扣方式
看了一下書,好像可以使用策略模式來滿足PM的需求

於是乎我建立了一個
CashPurchasing.cs
using System;

namespace DesignPattern.StrategyPattern
{
    /*現金收取父類別*/
    abstract class CashPurchasing
    {
        public abstract double acceptCash(double money);
    }
}



再新增一個滿xxx元送xxx點的class繼承CashPurchasing
CashReturn.cs
using System;

namespace DesignPattern.StrategyPattern
{
    /*滿xxx元送xxx點*/
    class CashReturn : CashPurchasing
    {
        private double moneyCondition = 0.0d;
        private double moneyReturn = 0.0d;
        /*初始化時必須要輸入紅利條件和紅利值,比如滿300送100,則moneyCondition為300,moneyReturn為100*/
        public CashReturn(string moneyCondition, string moneyReturn)
        {
            this.moneyCondition = double.Parse(moneyCondition);
            this.moneyReturn = double.Parse(moneyReturn);
        }

        public override double acceptCash(double money)
        {
            double result = money;
            if (money >= moneyCondition)
                result = moneyReturn;

            return result;
        }
    }
}


在新增另一個計算回饋的class一樣繼承CashPurchasing
CashRebate.cs
using System;

namespace DesignPattern.StrategyPattern
{
    /*回饋點數,繼承CashSuper*/
    class CashRebate : CashPurchasing
    {
        private double moneyRebate = 1d;
        /*初始化時,必需要輸入回饋率,如20%,就是0.2*/
        public CashRebate(string moneyRebate)
        {
            this.moneyRebate = double.Parse(moneyRebate);
        }

        public override double acceptCash(double money)
        {
            return money * moneyRebate;
        }
    }
}

PM要的兩種類別都寫好了!!
若以後PM再想到有的沒得運算邏輯就在新增類別即可
寫到這邊,好像似曾相識怎麼跟簡單工廠的做法一樣
再來是不是又要像簡單工廠一樣使用一個SimpleFactory來呼叫需要使用的類別?
所以邊要利用策略模式加上簡單工廠模式

於是乎又建立一個策略模式的class
CashContext.cs
using System;

namespace DesignPattern.StrategyPattern
{
    class CashContext
    {
        CashPurchasing cp = null;

        //根據條件返回相應的物件
        public CashContext(string type)
        {
            switch (type)
            {
                /*滿1000送100*/
                case "return":
                    CashReturn cr1 = new CashReturn("1000", "100");
                    cp = cr1;
                    break;
                /*回饋20%*/
                case "rebate":
                    CashRebate cr2 = new CashRebate("0.2");
                    cp = cr2;
                    break;
            }
        }

        public double GetResult(double money)
        {
            return cp.acceptCash(money);
        }
    }
}

再利用主控台跑一下這一個策略模式
using System;

namespace DesignPattern.StrategyPattern
{
    class RunGame
    {
        static void Main()
        {
            try
            {                
                Console.Write("請輸入玩家儲值的點數:");
                string strAmount = Console.ReadLine();

                /*PM要做回饋20%*/
                CashContext cp = new CashContext("rebate");
                Console.WriteLine("PM要做回饋20%,恭喜您可以額外獲得:" + cp.GetResult(Convert.ToInt32(strAmount)));

                /*PM要做滿1000送100*/
                cp = new CashContext("return");
                Console.WriteLine("PM要做滿1000送100,恭喜您可以額外獲得:" + cp.GetResult(Convert.ToInt32(strAmount)));

                Console.ReadLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine("您輸入有錯:" + ex.Message);
                Console.ReadLine();
            }

        }
    }
}

所以策略模式中我只要認識CashContext類別就好了
但上一篇的簡單工廠模式我要認識Gashapon與SimpleFactory類別
所以使用策略模式就降低了耦合度


比較 簡單工場模式 與 策略模式: 

1. 簡單工廠模式解決的是物件建立的問題,策略模式的重點則在用一個方式調用一系列演算法,使演算法的變動不會影響到用戶端
2. 對用戶端來說,使用簡單工廠模式必須 import 父類別跟 Factory 類別;但使用策略模式時只需 import 一個 Context 類別就行,降低耦合度

沒有留言:

張貼留言