簡單工廠-Simple Factory Pattern

設計模式系列

目的:定義一個簡單工廠,傳不同參數取得不同類別物件。

為什麼要用簡單工廠呢?
目的很簡單就是:做抽象降低耦合

什麼是抽象?
抽象就是在抽取事物的本質東西,剃除次要表面東西,這樣說可能不理解...
再把它具體化一下,把現實當中的某個東西,用程式表示出一個類或介面。
EX:例如香蕉、頻果、都是水果類。

耦合:就是你的模組與模組之間的依賴程度...(就是你的程式黏性,小心牽一髮動全身阿)。

 

以下就是簡單工廠的範例,分別由interface和abstract class用法
interface部分

    class Program
    {
        static void Main(string[] args)
        {
            Ifruit iFruit = SimpleFactory.ActEat("A");
            iFruit.Eat();
        }
    }

    public interface Ifruit
    {
        void Eat();
    }

    public class SimpleFactory
    {
        public static Ifruit ActEat(string fruitType)
        {
            switch (fruitType)
            {
                case "A":
                    return new Apple();
                case "B":
                    return new Banana();
                default:
                    return new Other();
            }
        }
    }

    class Apple : Ifruit
    {
        public void Eat() => Console.WriteLine("我要吃頻果");
    }
    class Banana : Ifruit
    {
        public void Eat() => Console.WriteLine("我要吃香蕉");
    }

    class Other : Ifruit
    {
        public void Eat() => Console.WriteLine("我不知道要吃什麼...");
    }

abstract class寫法

    class Program
    {
        static void Main(string[] args)
        {
            Fruit Fruit = SimpleFactory.ActEat("A");
            Fruit.Eat();
        }
    }

    public abstract  class Fruit
    {
       public  abstract  void Eat();
    }

    public class SimpleFactory
    {
        public static Fruit ActEat(string fruitType)
        {
            switch (fruitType)
            {
                case "A":
                    return new Apple();
                case "B":
                    return new Banana();
                default:
                    return new Other();
            }
        }
    }

    class Apple : Fruit
    {
        public override void Eat() => Console.WriteLine("我要吃頻果");
    }
    class Banana : Fruit
    {
        public override void Eat() => Console.WriteLine("我要吃香蕉");
    }

    class Other : Fruit
    {
        public override void Eat() => Console.WriteLine("我不知道要吃什麼...");
    }
    class Program
    {
        static void Main(string[] args)
        {
            Operation oper = OperationFactory.OperationCreate("+");
            oper.NumberA = 1;
            oper.NumberB = 2;
            Console.WriteLine(oper.GetResult());
        }
    }
    
    public class Operation
    {
        public int NumberA { get; set; }
        public int NumberB { get; set; }

        public virtual int GetResult()
        {
            int result = 0;
            result = NumberA + NumberB;
            return result;
        }
    }

    public class OperationAdd : Operation
    {
        public override int GetResult()
        { 
            return NumberA + NumberB;
        }
    }

    public class OperationSub : Operation
    {
        public override int GetResult()
        {
            return NumberA - NumberB;
        }
    }

    public class OperationFactory
    {
        public static Operation OperationCreate(string oper)
        {
            switch (oper)
            {
                case "+":
                    return new OperationAdd();
                case "-":
                    return new OperationSub();
                default:
                    return new Operation();
            }
        }
    }


缺點:違反OCP原則,因為每次加一個物件,都要針對簡單工廠進行修改,
          那怕是加一個switch case,仍然違背"不改代碼"原則
 


註記:
工廠方法:每種產品由一個工廠創建,一個工廠保存一個NEW基本完美,完全遵循,不改"程式"原則
抽象工廠:僅僅工廠方法複雜化,保存多個new,大工程會用上

案例:你要串接很多第三方支付,例如:你的線上付款,當中有很多家第三方支付,這時候可以

把它簡化變成,金流→有很多家第三支付→都有線上刷卡動作,寫一個現成簡化sample出來
 

簡單工廠,可以透過反射的做法方式去改良,後面的範例,我在補充上去^^

備註:

針對很容易變化的地方,以一個單獨的「類別」來處理它。

//想增加功能時,更改工廠類別。

補充加入小案例,來追加測試
 

    ​
    public interface IAventurer
    {
        string GetType();
    }

​
    public class Archer : IAventurer
    {
        public  string  GetType()
        {
            Console.WriteLine("我是弓箭手");
            return typeof(Archer).Name;
        }
    }

    public class Warrior : IAventurer
    {
        public string GetType()
        {
            Console.WriteLine("我是鬥士");
            return typeof(Warrior).Name;
        }
    }

    public class TrainingCamp
    {
        public static IAventurer tranAdventurer(string type)
        {
            switch (type)
            {
                case "archer":
                    Console.WriteLine("訓練一名弓箭手");
                    return new Archer();
                case "warrior":
                    Console.WriteLine("訓練一名鬥士");
                    return new Warrior();
                default: return null;
            }
        }
    }
    public class TrainingCampTest
    {
      
        [Test]
        public void Test()
        {
            IAventurer memberA = TrainingCamp.tranAdventurer("archer");
            IAventurer memberB = TrainingCamp.tranAdventurer("warrior");
            Assert.AreEqual(memberA.GetType(), "Archer");
            Assert.AreEqual(memberB.GetType(), "Warrior");
        }
    }


 

老E隨手寫