K書記錄-大話設計模式-簡單工廠

簡單工廠以及幾個範例和題外話

任務 : 做一個加減乘除計算機

UML :

1.先建立一個基本的計算類別

程式碼 :

    public class Operation
    {
        private double numberA;
        public double NumberA
        {
            get { return numberA; }
            set { numberA = value; }
        }
        private double numberB;
        public double NumberB
        {
            get { return numberB; }
            set { numberB = value; }
        }
        public virtual double GetResult()
        {
            double result = 0;
            return result;
        }
    }

說明 : 將基本的計算內容實現,由於是兩個數值的計算,所以先建立number1和number2的數值待運算,之後建立GetResult的方法把計算結果列出來。

 

2.建立加、減、乘、除法類別,繼承計算類別

程式碼 :

public class OperationAdd : Operation
    {
        public override double GetResult()
        {
            double result = 0;
            result = NumberA + NumberB;
            return result;
        }
    }
    public class OperationSub : Operation
    {
        public override double GetResult()
        {
            double result = 0;
            result = NumberA - NumberB;
            return result;
        }
    }
    public class OperationMul : Operation
    {
        public override double GetResult()
        {
            double result = 0;
            result = NumberA * NumberB;
            return result;
        }
    }
    public class OperationDiv : Operation
    {
        public override double GetResult()
        {
            double result = 0;
            if (NumberB == 0)
            {
                throw new Exception("除數不得為0");
            }
            result = NumberA / NumberB;
            return result;
        }
    }

說明 : 先繼承了父類別,所以自身就擁有了Number1,Number2和GetResult(),不過計算法不同,直接使用override複寫掉父類別的GetResult()方法,改成加減乘除的計算。

 

3.建立計算工廠

程式碼 :

    public class OperationFactory
    {
        public static Operation CreateOperate(string operate)
        {
            Operation output = null;
            switch (operate)
            {
                case "+":
                    output = new OperationAdd();
                    break;
                case "-":
                    output = new OperationSub();
                    break;
                case "*":
                    output = new OperationMul();
                    break;
                case "/":
                    output = new OperationDiv();
                    break;

                default:
                    break;
            }
            return output;
        }
    }

 

說明 : 建立一個回傳計算類別的工廠,此工廠可以是加、減、乘、除法類別,利用傳入的參數operate去選擇需要的計算類別。

 

4.使用計算工廠

程式碼 :

        static void Main(string[] args)
        {
            Operation operation;
            operation = OperationFactory.CreateOperate("/");
            operation.NumberA = 5;
            operation.NumberB = 2;
            double result = operation.GetResult();
            Console.WriteLine(result);
            Console.ReadLine();

        }

說明 :

a.使用計算工廠的CreateOperate方法,並傳入+、-、*、/選擇要製造的計算方式

b.設定要計算的數值1、數值2。

c.取得計算後的答案

d.寫出答案

 

小結 :

先創一個計算類別讓其他計算的類別繼承=>

宣告的時候可以用共同的父類別宣告。

 

分別將每個計算類別寫上計算邏輯=>

複寫父類別的資料改為自己的計算方法。

 

建立一個工廠依照傳入的字串產出不同的計算類別=>

隱藏計算的類別與方法,使用者只要輸入運算子就能得到該運算子的算法。

 

使用GetResult()=>

使用者可以不用知道當初工廠產出了甚麼給你,你只要將工廠產出的那個東西使GetResult()方法就會得到對應的答案,內部用哪個類別算,怎麼算都跟使用者沒關係。

 

使用心得 :

簡單工廠可以讓使用者擁有較少的知識就可以達成需要的功能,而且使用這個方法讓程式碼更好維護,每個類別都區分開來,要改哪個算法就去哪改,要是使用最直覺的if-else方法的話,全部的計算都會擠在一起,要改就要先去找if的分支,然後找到對應的修改地方,這樣會造成後續的維護困難。

不過,要是計算邏輯夠單純且修改機率極低的話倒是可以寫出最直覺的方法來處理當下狀況就好,要是繞了一圈設計模式寫了一個單純的邏輯反而多麻煩。

 

 

 

加碼 : 手機工廠

程式碼 :

    public abstract class Phone
    {
         private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public abstract string GetInfo();
    }
    public class ApplePhone : Phone
    {
        public override string GetInfo()
        {
            return $"{Name} 是 水果手機";
        }
    }
    public class SonyPhone : Phone
    {
        public override string GetInfo()
        {
            return $"{Name} 是 $ony手機";
        }
    }
 public class PhoneFactory
    {
        public static Phone GetPhone(string brand)
        {
            Phone phone = null;
            switch (brand)
            {
                case "Apple":
                    phone = new ApplePhone();
                    break;
                case "Sony":
                    phone = new SonyPhone();
                    break;
                default:
                    break;
            }
            return phone;
        }
    }
        static void Main(string[] args)
        {
            Phone phoneA = PhoneFactory.GetPhone("Apple");
            phoneA.Name = "PhoneA";
            Console.WriteLine(phoneA.GetInfo());

            Phone phoneB = PhoneFactory.GetPhone("Sony");
            phoneB.Name = "PhoneB";
            Console.WriteLine(phoneB.GetInfo());
            Console.ReadLine();
        }

執行結果 : 

說明 :

        手機有名字也有手機資訊,蘋果手機有自己的資訊,Sony手機有自己的資訊,某工廠可以依照需求生產這兩款手機,當初工廠給你甚麼手機就會有甚麼手機的資訊。

 

 

加碼 : 形狀工廠

程式碼 : 

    public interface IShape
    {
        void draw();
    }
    public class MyRectangle : IShape
    {
        public void draw()
        {
            Console.WriteLine("Draw MyRectangle");
        }
    }
    public class MyCircle : IShape
    {
        public void draw()
        {
            Console.WriteLine("Draw MyCircle");
        }
    }
    public static class ShapeFactory
    {
        public static IShape CreateFactory(string shapeType)
        {
            switch (shapeType)
            {
                case "Rectangle":
                    return new MyRectangle();
                case "Circle":
                    return new MyCircle();
                default:
                    break;
            }
            return null;
        }
    }
        static void Main(string[] args)
        {
            IShape shape = ShapeFactory.CreateFactory("Circle");
            shape.draw();

            IShape shape2 = ShapeFactory.CreateFactory("Rectangle");
            shape2.draw();

            Console.ReadLine();
        }

執行結果 : 

說明 :

        方形、圓形都是形狀,只要是形狀就可以繪製,有一個形狀產生工廠可以產生方形和圓形,工廠給圓形就畫圓形,方形就方形。

 

 

題外話 : 

其實這樣也能解決問題(使用運算子多載)

程式碼 : 

    public readonly struct Fraction
    {
        private readonly int num;
        private readonly int den;
        public Fraction(int numerator , int denominator)
        {
            if (denominator == 0)
            {
                throw new ArgumentException("Denominator cannot be zero.", nameof(denominator));
            }

            num = numerator;
            den = denominator;
        }
        public static Fraction operator +(Fraction a) => a;
        public static Fraction operator -(Fraction a) => new Fraction(-a.num, a.den);
        public static Fraction operator +(Fraction a, Fraction b)
            => new Fraction(a.num * b.den + b.num * a.den, a.den * b.den);
        public static Fraction operator -(Fraction a, Fraction b)
            => new Fraction(a.num * b.den - b.num * a.den, a.den * b.den);
        public static Fraction operator *(Fraction a, Fraction b)
            => new Fraction(a.num * b.num, a.den * b.den);
        public static Fraction operator /(Fraction a, Fraction b)
            => new Fraction(a.num * b.den, a.den * b.num);
        public override string ToString() => $"{num} / {den}";
    }
        static void Main(string[] args)
        {
            var a = new Fraction(5, 4);
            var b = new Fraction(1, 2);
            Console.WriteLine(-a);
            Console.WriteLine(a+b);
            Console.WriteLine(a-b);
            Console.WriteLine(a*b);
            Console.WriteLine(a/b);
            Console.ReadLine();
        }

執行結果 : 

說明 : 

只是想到有這個方法就貼上來了。

 

 

 

建議動手刻一次程式碼,寫的過程中可能會有許多小問題出來,或是會有新的想法、新的理解閃過腦海中,這些都是複製+貼上無法學到的。

 

新手上路,若有錯誤請不吝嗇指教,謝謝。