設計模式-C#實現簡單工廠模式

妙妙屋(zy)發表於2024-07-17

前言

上一篇文章寫了如何使用RabbitMQ做個簡單的傳送郵件專案,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的訊息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧!
在瞭解簡單工廠模式之前,我們要知道C#是一款物件導向的高階程式語言。它有3大特性,封裝、繼承、多型。

簡述

工廠模式(Factory Pattern)是一種常用的設計模式,屬於建立型模式,它提供了一種建立物件的最佳方式。在工廠模式中,我們建立物件時不會對客戶端暴露建立邏輯,並且是透過使用一個共同的介面來指向新建立的物件。
工廠模式的核心是定義一個建立產品物件的工廠介面,將實際建立工作推遲到子類當中。這樣客戶端可以無需指定具體產品的類,只需透過工廠類即可得到所需的產品物件。

工廠模式主要分為三種型別:簡單工廠模式(Simple Factory Pattern)、工廠方法模式(Factory Method Pattern)和抽象工廠模式(Abstract Factory Pattern)。
本文主要講解簡單工廠模式(Simple Factory Pattern)。

案例帶入

下面使用C#控制檯程式去寫一個簡易的計算器,實現加減乘除。如果我沒學過設計模式,我會這麼寫:

static void Main(string[] args)  
{  
    Console.WriteLine("請輸入數字A:");  
    string A = Console.ReadLine();  
    Console.WriteLine("請選擇運算子號:(+、-、*、/):");  
    string op = Console.ReadLine();  
    Console.WriteLine("請輸入數字B:");  
    string B = Console.ReadLine();  
    string result = "";  
    switch (op)  
    {        
	    case "+":  
            result = Convert.ToString(Convert.ToDouble(A) + Convert.ToDouble(B));  
            break;  
        case "-":  
            result = Convert.ToString(Convert.ToDouble(A) - Convert.ToDouble(B));  
            break;  
        case "*":  
            result = Convert.ToString(Convert.ToDouble(A) * Convert.ToDouble(B));  
            break;  
        case "/":  
            result = Convert.ToString(Convert.ToDouble(A) / Convert.ToDouble(B));  
            break;  
        default:  
            Console.WriteLine("輸入的運算子號有誤!");  
            break;  
    }    
    Console.WriteLine("結果:" + result);  
}

上述程式碼乍一看沒問題,實則隱藏了很多陷阱,比如:

  1. 變數命名不規範
  2. 除數為0怎麼辦
  3. 輸入的不是數字怎麼辦
  4. ......

最佳化

我們用物件導向的思想進行最佳化,主要體現在:可維護、可複用、可擴充套件、靈活性幾個方面。透過封裝、繼承、多型來降低程式的耦合度。

封裝

我們可以將運算邏輯封裝成一個方法去實現,讓主方法減輕負擔。封裝後:
Operation

public class Operation
{
    public static double GetResult(double num1, double num2, string op)
    {
        double result = 0d;
        switch (op)
        {
            case "+":
                result = num1 + num2;
                break;
            case "-":
                result = num1 - num2;
                break;
            case "*":
                result = num1 * num2;
                break;
            case "/":
                result = num1 / num2;
                break;
        }
        return result;
    }
}

Main方法

static void Main(string[] args)
{
	try
	{
		Console.WriteLine("請輸入數字A:");
		string strNumA = Console.ReadLine();
		Console.WriteLine("請選擇運算子號:(+、-、*、/):");
		string op = Console.ReadLine();
		Console.WriteLine("請輸入數字B:");
		string strNumB = Console.ReadLine();
		string result = "";
		result = Convert.ToString(Operation.GetResult(Convert.ToDouble(strNumA), Convert.ToDouble(strNumB), op));
		Console.WriteLine("結果:" + result);
	}
	catch (Exception e)
	{
		Console.WriteLine("發生異常:" + e.Message);
	}
}

松耦合

當我們完成封裝後開始思考一個問題,如果後面有新的需求,需要增加一個開根執行,應該如何去修改?如果是我,我會在switch裡面加一個分支,但是這樣耦合度太高。我明明只需要去開根,但是卻要讓加減乘除參與進來,所以我們應該將加減乘除運算分離出來。
最佳化耦合度:

public class Operation
{
    private double _num1;
    private double _num2;
    public double Num1 { get => _num1; set => _num1 = value; }
    public double Num2 { get => _num2; set => _num2 = value; }
    public virtual double GetResult()
    {
        return 0;
    }
}

//加法類
public class AddOperation : Operation
{
    public override double GetResult()
    {
        return Num1 + Num2;
    }
}
//減法類
public class SubtractOperation : Operation
{
    public override double GetResult()
    {
        return Num1 - Num2;
    }
}
//乘法類
public class MultiplyOperation : Operation
{
    public override double GetResult()
    {
        return Num1 * Num2;
    }
}
//除法類
public class DivideOperation : Operation
{
    public override double GetResult()
    {
        if (Num2 == 0)
            throw new DivideByZeroException("除數不能為0");
        return Num1 / Num2;
    }
}  

我建立了Operation基類,並定義了2個成員變數_num1_num2,同時定義了一個GetResult虛方法。同時分別建立了加減乘除子類去重寫GetResult方法來降級耦合度。

迴歸正題(簡單工廠模式)

我們需要透過簡單工廠模式,來讓程式知道該例項化誰。需要來建立一個工廠類:

public class OperationFactory
{
    public static Operation CreateOperation(string operation)
    {
        switch (operation)
        {
            case "+":
                return new AddOperation();
            case "-":
                return new SubtractOperation();
            case "*":
                return new MultiplyOperation();
            case "/":
                return new DivideOperation();
            default:
                return null;
        }
    }
}

建立了工廠類有什麼好處呢,好處就是,只需要輸入運算子號,工廠就能自己例項化出合適的物件,透過多型,返回父類的方法實現了計算器的計算結果。
Main方法
透過簡單工廠模式,讓我們在計算加減乘除的時候只需要去增加對應的子類就行了,下面的程式碼進行加法執行時,透過傳入+號讓工廠去幫我們例項化子類。

static void Main(string[] args)  
{  
    try  
    {  
        // 簡單工廠模式  
        var oper = OperationFactory.CreateOperation("+");  
        oper.Num1 = 10;  
        oper.Num2 = 5;  
        Console.WriteLine(oper.GetResult());  
    }    
    catch (Exception e)  
    {        
    Console.WriteLine("發生異常:" + e.Message);  
    }
}

類圖

講完簡單工廠模式後,簡簡單單復現一下類圖:
image

小小知識點

  • 介面:強調“做什麼”,即介面定義了物件應該做什麼,而不關心它是如何做的。
  • 虛方法:強調“如何做”,即基類提供了一種實現方式,但允許派生類根據需要進行修改。

參考資料

  • 熟讀並反覆背誦大話設計模式-程傑出版

相關文章