從真實專案中摳出來的設計模式——第一篇:策略模式

一線碼農發表於2017-01-24

  有時候因為種種原因導致我們會寫出很多醜陋的程式碼,比如趕工時,短暫性的偷懶,不會設計模式等等導致程式碼沉積,一個cs上萬行程式碼這樣場景是有發生,

當然這裡也包括我。。。所以時間充裕一點之後就想重構一下,畢竟專案中的需求是不斷變更的,面對需求變更,儘量做到最低限度的修改程式碼,最大化的擴充

新程式碼,還有一點就是不要過分的追求設計模式,做到適可為止,太設計模式了會導致類太多,不好管理,在專案開發中,其實仔細考慮一下,你會發現很多業

務邏輯都有相應的設計模式幫你優化,畢竟這些都是前輩們踩了無數的坑,經過無數的苦難留下來的智慧結晶。很多人列舉設計模式都喜歡用生活中的例子,但

畢竟生活中的例子如何應用到專案中,對我們程式設計師來說還是比較抽象的,所以這裡我就列舉我們實際的業務邏輯場景。

 

一:實際場景介紹

    我們在做千人千面的時候,為了防止各大郵箱服務商對我們的郵件營銷內容做遮蔽處理,我們採用的策略就是眾多模板庫中隨機抽取一封html樣式表,然後結

合具體的商品列表生成完全不一樣風格的營銷內容郵件,爭取最大可能的不被遮蔽,而使用者自己通過我們系統做的營銷郵件,我們又不能隨機傳送,而是使用者生成

什麼樣的郵件,我們就發什麼樣的郵件,ok,現在這裡就有兩種策略場景了,兩種場景的最終目的都是生成郵件內容,對吧。

 

1. 普通商家做營銷活動的郵件,這種策略沒什麼好說的,是什麼就發什麼。

2.千人千面場景下的營銷活動郵件,這種策略採用隨機抽取的模式,

 

目前來說,我們就這兩種場景,誰也指不定以後還會不會有其他的策略出來,所以有必要用策略模式玩一下。

 

二:構建UML

    從vs2005開始就有一個強大的功能,根據cs檔案自動生成uml類圖,非常的直觀也更容易的幫助我們設計更加合理的類圖。

 

上面就是策略模式的uml圖,各個策略類中都有一個Setup方法,用來設定email的內容,具體各個類中的程式碼如下:

 

<1> AbstractStrategy

    public abstract class AbstractStrategy
    {
        public abstract void Setup();
    }

 

<2> RandStrategy

    public class RandStrategy : AbstractStrategy
    {
        public override void Setup()
        {
            Console.WriteLine("千人千面模式下的郵件傳送");
        }
    }

 

<3> StraightStrategy 

    public class StraightStrategy : AbstractStrategy
    {
        public override void Setup()
        {
            Console.WriteLine("普通商家傳送的郵件");
        }
    }

 

<4>StrategyContext

    public class StrategyContext
    {
        AbstractStrategy strategy = null;

        public void SetStrategy(AbstractStrategy strategy)
        {
            this.strategy = strategy;
        }

        public void Setup()
        {
            this.strategy.Setup();
        }
    }

 

<5> Program

    class Program
    {
        static void Main(string[] args)
        {
            StrategyContext context = new StrategyContext();

            //設定“隨機策略“
            context.SetStrategy(new RandStrategy());

            context.Setup();

            //設定 ”直接傳送“
            context.SetStrategy(new StraightStrategy());

            context.Setup();
        }
    }

 

最後我們執行一下:

 

上面就是一個最簡單的策略模式,當我們設定不同的策略,就會執行相應的行為,實際當中,並不會這麼簡單,畢竟設計模式只是一個最優化的提煉,排除干擾看本質。

 

三:生產應用

   首先生產中我們的AbstractSetup中的Setup方法肯定是要帶有引數的,而不是簡單的無參,如下:

    /// <summary>
    /// 簡訊,郵件,彩信設定模型
    /// </summary>
    public abstract class AbstractSetup
    {
        public abstract void Setup(LeafletEntity leaflet, DataRow row);
    }

 

然後直接賦值的邏輯也非常的簡單,需要根據資料庫中設定的業務邏輯判斷。

   public class StraightSetup : AbstractSetup
    {
        public override void Setup(LeafletEntity leaflet, DataRow row)
        {
            //非顧問
            leaflet.Title = MySqlDbHelper.GetString(row, "title");

            leaflet.SMSContent = leaflet.CommunicationtypeEnum.HasFlag(CommunicationTypeEnum.簡訊) ? MySqlDbHelper.GetString(row, "content") : string.Empty;
            leaflet.EDMContent = leaflet.CommunicationtypeEnum.HasFlag(CommunicationTypeEnum.郵件) ? MySqlDbHelper.GetString(row, "content") : string.Empty;
            leaflet.MMSContent = leaflet.CommunicationtypeEnum.HasFlag(CommunicationTypeEnum.彩信) ? MySqlDbHelper.GetString(row, "content") : string.Empty;

            leaflet.SendSMSCount = Convert.ToInt32(row["sendcount"]);
        }
    }

 

接下來就是隨機抽取邏輯,這個也是通過讀取隨機表來進行各種操作,簡單的程式碼如下:

  public class RandSetup : AbstractSetup
    {
        EventMarketingBLLNew eventMarketingBLLNew = new EventMarketingBLLNew();

        public override void Setup(LeafletEntity leaflet, DataRow row)
        {
            var eventMarketingInfo = eventMarketingBLLNew.GetEventMarketingInfo(leaflet.MarketingID, leaflet.ShopID);

            if (eventMarketingInfo != null)
            {
                //“簡訊”和“郵件”資訊
                var communicationInfo = eventMarketingInfo.EventmarketingSmsEdmContentList.OrderBy(m => Guid.NewGuid())
                                                          .FirstOrDefault();

                if (communicationInfo == null) return;

                if (leaflet.CommunicationtypeEnum.HasFlag(CommunicationTypeEnum.郵件))
                {
                    //第三步:動態生成郵件模板
                    var styleInfo = CacheUtil.GetRandomEmailStyle();

                    var tuple = new EdmDraftBoxBLL().GetEdmHtmlTitle(communicationInfo.EDMJson, styleInfo.StyleId);

                    leaflet.Title = tuple.Item1;
                    leaflet.EDMContent = tuple.Item2;
                    leaflet.Header = tuple.Item3;
                    leaflet.SendSMSCount = 1;
                }

                if (leaflet.CommunicationtypeEnum.HasFlag(CommunicationTypeEnum.簡訊))
                {
                    leaflet.SMSContent = communicationInfo.SMSContent;
                    leaflet.SendSMSCount = communicationInfo.SMSCount;
                }

                if (leaflet.CommunicationtypeEnum.HasFlag(CommunicationTypeEnum.彩信))
                {
                    leaflet.MMSContent = communicationInfo.MMSContent;
                }
            }
        }
    }

 

最後就是策略上下文:

    public class SetupContext
    {
        AbstractSetup abstractSetup = null;

        public void Set(AbstractSetup abstractSetup)
        {
            this.abstractSetup = abstractSetup;
        }

        public void Setup(LeafletEntity leaflet, DataRow row)
        {
            this.abstractSetup.Setup(leaflet, row);
        }
    }

 

好了,這個就是給大家演示的策略模式,簡單來說就是一句話:針對同一命令或行為,不同的策略做不同的動作。 

 

相關文章