1. 程式人生 > >【設計模式】簡單工廠模式——以一個簡單的計算器為例

【設計模式】簡單工廠模式——以一個簡單的計算器為例

本文內容參考自《大話設計模式》(程傑 著)

注:以下程式碼為C#實現

1.拙劣的程式碼

class Program

{

    static void Main(string[] args)

    {

        Console.Write("請輸入數字A:");

        string A = Console.ReadLine();

        Console.Write("請選擇運算子號(+、-、*、/):");

        string B = Console.ReadLine();

        Console.Write("請輸入數字B:"
); string C = Console.ReadLine(); string D = ""; if (B == "+") D = Convert.ToString(Convert.ToDouble(A) + Convert.ToDouble(C)); if (B == "-") D = Convert.ToString(Convert.ToDouble(A) - Convert.ToDouble(C)); if (B == "*") D = Convert.ToString
(Convert.ToDouble(A) * Convert.ToDouble(C)); if (O == "/") D = Convert.ToString(Convert.ToDouble(A) / Convert.ToDouble(C)); Console.WriteLine("結果是:" + D); } }

毛病:命名不規範,判斷分支做多次無用功,除數為0時出錯,輸入不是數字……

2.規範化



class Program

{

    static void Main(string[] args)

    {

        try

        {

            Console.Write
("請輸入數字A:"); string strNumberA = Console.ReadLine(); Console.Write("請選擇運算子號(+、-、*、/):"); string strOperate = Console.ReadLine(); Console.Write("請輸入數字B:"); string strNumberB = Console.ReadLine(); string strResult = ""; switch (strOperate) { case "+": strResult = Convert.ToString(Convert.ToDouble(strNumberA) + Convert.ToDouble(strNumberB)); break; case "-": strResult = Convert.ToString(Convert.ToDouble(strNumberA) - Convert.ToDouble(strNumberB)); break; case "*": strResult = Convert.ToString(Convert.ToDouble(strNumberA) * Convert.ToDouble(strNumberB)); break; case "/": if (strNumberB != "0") strResult = Convert.ToString(Convert.ToDouble(strNumberA) / Convert.ToDouble(strNumberB)); else strResult = "除數不能為0"; break; } Console.WriteLine("結果是:" + strResult); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("您的輸入有錯:" + ex.Message); } } }

以上程式碼規範了,但是可重用性差!

3.業務的封裝

Operation運算類

public class Operation

{

    public static double GetResult(double numberA, double numberB, string operate)

    {

        double result = 0d;

        switch (operate)

        {

            case "+":

                result = numberA + numberB;

                break;

            case "-":

                result = numberA - numberB;

                break;

            case "*":

                result = numberA * numberB;

                break;

            case "/":

                result = numberA / numberB;

                break;

        }

        return result;

    }

}

客戶端程式碼

static void Main(string[] args)

{

    try

    {

        Console.Write("請輸入數字A:");

        string strNumberA = Console.ReadLine();

        Console.Write("請選擇運算子號(+、-、*、/):");

        string strOperate = Console.ReadLine();

        Console.Write("請輸入數字B:");

        string strNumberB = Console.ReadLine();

        string strResult = "";

        strResult = Convert.ToString(Operation.GetResult(Convert.ToDouble(strNumberA),

        Convert.ToDouble(strNumberB), strOperate));

        Console.WriteLine("結果是:" + strResult);

        Console.ReadLine();

    }

    catch (Exception ex)

    {

        Console.WriteLine("您的輸入有錯:" + ex.Message);

    }

}

問題:如果我要增加其他運算,或者是想要修改運算的法則,那麼其他程式碼都會受到影響,比如要重新編譯,除錯等等。

4.鬆耦合

Operation運算類

public class Operation

{

    private double _numberA = 0;

    private double _numberB = 0;



    public double NumberA

    {

        get  {  return _numberA;  }

        set  {  _numberA = value;  }

    }

    public double NumberB

    {

        get  {  return _numberB;  }

        set  {  _numberB = value;  }

    }

    public virtual double GetResult()

    {

        double result = 0;

        return result;

    }

}

加減乘除類

class OperationAdd : Operation

{

    public override double GetResult()

    {

        double result = 0;

        result = NumberA + NumberB;

        return result;

    }

}

class OperationSub : Operation

{

   public override double GetResult()

    {

        double result = 0;

        result = NumberA - NumberB;

        return result;

    }

}

class OperationMul : Operation

{

    public override double GetResult()

    {

        double result = 0;

        result = NumberA * NumberB;

        return result;

    }

}

class OperationDiv : Operation

{

    public override double GetResult()

    {

        double result = 0;

        if (NumberB==0)

            throw new Exception("除數不能為0。");

        result = NumberA / NumberB;

        return result;

    }

}

在這裡,我們定義了一個虛擬函式,然後其他運算繼承操作類並實現該函式,這樣子,如果要增加其他運算,只需要增加一個類來繼承操作類就可以了,而且單個操作的修改完全不影響其他的運算!

5.簡單工廠模式

使用上面程式碼之後,我們在客戶端需要例項化相應的類,比如‘+’操作需要例項化OperationAdd,減操作需要例項化OperationSub,這樣子暴露給客戶的資訊太多了,客戶必須知道每個操作它對應的類!

使用簡單的工廠模式可以避免這個問題:
簡單運算工廠類

public class OperationFactory

{

    public static Operation createOperate(string operate)

    {

        Operation oper = null;

        switch (operate)

        {

            case "+":

                oper = new OperationAdd();

                break;

            case "-":

                oper = new OperationSub();

                break;

            case "*":

                oper = new OperationMul();

                break;

            case "/":

                oper = new OperationDiv();

                break;

        }

        return oper;

    }

}

客戶端程式碼

Operation oper;

oper = OperationFactory.createOperate(“+”);

oper.NumberA = 1;

oper.NumberB = 2;

double result = oper.GetResult();

如果一來,客戶端就簡化了很多,它只需要知道 OperationFactory,並通過createOperate傳入相應的操作就可以了!

當我們需要修改加法運算時,只需要修改OperationAdd,當我們需要增加其他運算時,只需要增加相應的運運算元類,並在運算類工廠中增加分支即可。

同時,介面顯示和我們的業務邏輯也是分離的~

UML圖:
這裡寫圖片描述