2016年7月11日 星期一

創建者模式 Builder Pattern

PM:小奇,我發現上個月營收不好
PM:這次豁出去了!
PM:直接來賣整套套裝了...
PM:也就是轉一次就給你一個指定套裝,但是數值好壞就看個人運氣了
PM:所以目前總共有5套,但是改版後可能會新增2套
我:好的,沒問題

所以這次的需求,是要抽套裝,套裝裡面有頭盔、上衣、褲子、手套、鞋子
所以這5樣套裝的東西是固定的,只是套裝的種類是會變來變去的
如:王朝套裝、帝國套裝、雜七雜八套裝

PM又說了,改版後會在新增兩件套裝,所以之後會在加兩件套裝上去
於是使用創建者模式寫寫看

using System;

namespace DesignPattern.BuilderPattern
{
    class Run
    {
        static void Main(string[] args)
        {
            Director director = new Director();
            Bulider bulider = new KingSet();    //獲取王朝套裝
            director.setBulider(bulider);
            director.create();

            Console.WriteLine("----------");

            bulider = new EmpireSet();  //獲取帝國套裝
            director.setBulider(bulider);
            director.create();
            Console.ReadLine();
        }

        //套裝的裝備項目
        interface Bulider
        {
            //獲得頭盔
            void getHat();
            //獲得上衣     
            void getCoat();
            //獲得褲子      
            void getPants();
            //獲得手套    
            void getGloves();
            //獲得鞋子
            void getShoe();       
        }

        //統一由指揮者 class 執行生產步驟
        class Director
        {
            private Bulider builder;
            public void setBulider(Bulider builder)
            {
                this.builder = builder;
            }
            public void create()
            {
                this.builder.getHat();
                this.builder.getCoat();
                this.builder.getPants();
                this.builder.getGloves();
                this.builder.getShoe();
            }
        }

        //王朝套裝
        class KingSet : Bulider
        {
            public void getHat()
            {
                Console.WriteLine("獲得王朝套裝-頭盔");
            }
            public void getCoat()
            {
                Console.WriteLine("獲得王朝套裝-上衣");
            }

            public void getPants()
            {
                Console.WriteLine("獲得王朝套裝-褲子");
            }

            public void getGloves()
            {
                Console.WriteLine("獲得王朝套裝-手套");
            }

            public void getShoe()
            {
                Console.WriteLine("獲得王朝套裝-鞋子");
            }
        }

        //帝國套裝
        class EmpireSet : Bulider
        {
            public void getHat()
            {
                Console.WriteLine("獲得帝國套裝-頭盔");
            }
            public void getCoat()
            {
                Console.WriteLine("獲得帝國套裝-上衣");
            }

            public void getPants()
            {
                Console.WriteLine("獲得帝國套裝-褲子");
            }

            public void getGloves()
            {
                Console.WriteLine("獲得帝國套裝-手套");
            }

            public void getShoe()
            {
                Console.WriteLine("獲得帝國套裝-鞋子");
            }
        }
    }
}

所以這邊我創建了一個interface  Bulider內容就是套裝的項目,這些都是固定的
然後又創建了一個Director類別,負責產生套裝
然後創建王朝套裝(KingSet)的類別繼承Bulider,來實做得到的內容
所以改版後,新增的兩件套裝,我就可以在新增兩個類別來實做新的套裝
這邊也就不會動到之前的套裝的類別

2016年7月10日 星期日

外觀模式 Facade Pattern

PM:小奇奇,在嗎?
我: 是的,I am here
PM:我又想弄一個轉蛋活動,就是轉一次可以獲得隨機屬性裝備(頭盔、上衣、下衣、手套、鞋子)等等...
PM:但是我有兩種金額的轉蛋,50元可以轉出上衣、下衣,但是100元可以轉出整套的裝備
我:好的,沒問題喔

於是我將code先寫成這樣
using System;
namespace DesignPattern.FacadePattern
{
    class Run
    {
        static void Main(string[] args)
        {            
            Console.WriteLine("50元轉蛋:");
            Gashapon gash = new Gashapon();
            gash.getCoat();
            gash.getPants();

            Console.WriteLine("100元轉蛋:");
            gash.getHat();
            gash.getCoat();
            gash.getPants();
            gash.getGloves();
            gash.getShoe();
            Console.Read();
        }

        class Gashapon
        {
            //獲得頭盔
            public void getHat()
            {
                Console.WriteLine("獲得隨機屬性頭盔");                
            }

            //獲得上衣
            public void getCoat()
            {
                Console.WriteLine("獲得隨機屬性上衣");
            }

            //獲得褲子
            public void getPants()
            {
                Console.WriteLine("獲得隨機屬性褲子");
            }
            
            //獲得手套
            public void getGloves()
            {
                Console.WriteLine("獲得隨機屬性手套");
            }

            //獲得鞋子
            public void getShoe()
            {
                Console.WriteLine("獲得隨機屬性鞋子");
            }

        }
    }
}
先建立一個Gashapon轉蛋的類別,裡面有getHat()、getCoat()、getPants()、getGloves()、getShoe()分別是獲得各種裝備的方法

這樣寫也沒什麼不對,只是如果PM又要加碼武器(刀、劍、槍....)等等
這樣不就又多了好多個方法,這樣程式變的很雜亂
所以可以透過外觀模式來整理一下介面
using System;

namespace DesignPattern.FacadePattern
{
    class Run
    {
        static void Main(string[] args)
        {
            Console.WriteLine("50元轉蛋:");
            GashaponFacade gash = new GashaponFacade();
            gash.get50Item();

            Console.WriteLine("100元轉蛋:");
            gash.get100Item();
            Console.Read();
        }

        class GashaponFacade
        {
            Gashapon gash;
            public GashaponFacade()
            {
                gash = new Gashapon();
            }

            public void get50Item()
            {
                gash.getCoat();
                gash.getPants();
            }

            public void get100Item()
            {
                gash.getHat();
                gash.getCoat();
                gash.getPants();
                gash.getGloves();
                gash.getShoe();
            }
        }

        class Gashapon
        {
            //獲得頭盔
            public void getHat()
            {
                Console.WriteLine("獲得隨機屬性頭盔");
            }

            //獲得上衣
            public void getCoat()
            {
                Console.WriteLine("獲得隨機屬性上衣");
            }

            //獲得褲子
            public void getPants()
            {
                Console.WriteLine("獲得隨機屬性褲子");
            }

            //獲得手套
            public void getGloves()
            {
                Console.WriteLine("獲得隨機屬性手套");
            }

            //獲得鞋子
            public void getShoe()
            {
                Console.WriteLine("獲得隨機屬性鞋子");
            }

        }
    }
}
這邊新增了一個GashaponFacade類別,來整理出購買50元或100元會得到的虛寶
可以看到我們在使用get50Item()可以不需要去接觸那些繁瑣的事,只要透過get50Item()為我們處理50元的虛寶即可,外觀模式的威力就在於此。

另外,在重構時我們可能會接觸到充滿耦合、邏輯錯綜複雜的程式,其實我們也可以先為這塊加入外觀模式,將不同階層的程式透過中間層隔離,接著在為各區塊進行重構,我們可以就中間層進行測試,就可以避免造成測試不易的問題。