iT邦幫忙

2023 iThome 鐵人賽

DAY 15
0
自我挑戰組

初階面試常見題目彙整系列 第 15

初階面試常見題目回答-工廠方法模式(Factory Method Pattern)-鐵人賽第十五日

  • 分享至 

  • xImage
  •  

在說完簡單工廠模式,
這時候就來說說工廠方法模式(Factory Method Pattern)吧!

工廠方法模式(Factory Method Pattern)是一種軟體設計模式,同樣屬於創建型模式。
它將物件的創建過程封裝在一個工廠方法內,使得不同的子類可以根據需要創建不同的物件,從而實現了客戶端代碼和具體物件之間的解耦。

工廠方法模式主要由以下幾個元素組成:

Creator(創建者):這是一個抽象類,它聲明了一個抽象的工廠方法,用於返回一個產品對象。
ConcreteCreator(具體創建者):這是Creator的子類,它實現了工廠方法,用於創建具體的產品對象。
Product(產品):定義產品的介面,是一個抽象類別或介面。
ConcreteProduct(具體產品):這是Product的實現類,它實現了產品接口中的方法,由Factory創建。

可以看到昨天的Factory(工廠)替換為ConcreteCreator(具體創建者)並多了Creator(創建者),
就以介紹來說看起來都大同小異,
或什麼不直接使用簡單工廠模式就夠了,
那麼便來喚回所謂的SOLID來看看吧!

有沒有發現其實簡單工廠模式在
單一職責原則(Single Responsibility Principle,SRP)有些微可能違反
開放封閉原則(Open-Closed Principle,OCP)如果要更改就會違反

簡單工廠基於一個中央工廠生產了多個產品,
如果一不小心負責了不同的事情不就違反單一職責
而每次替換都要更改程式碼。

這兩個問題都能透過一個奇妙的方式解決,
把每一間工廠通通獨立出來就行了,
只要每一次新增一間就產生一個對應的工廠,
這就是工廠模式。

    // 定義抽象的 SupplierServiceFactory 介面
    public interface SupplierServiceFactory
    { 
        // 定義抽象的 GetCarInfomationService 方法
        public ICarInfomationService GetCarInfomationService();
    }

    // 定義具體的 VOLVOServiceFactory 類別
    public class VOLVOServiceFactory : SupplierServiceFactory
    {
        // 實現 GetCarInfomationService 方法  
        public ICarInfomationService GetCarInfomationService()
        {
            // 創建 VOLVOService 物件 
            return new VOLVOService();
        }
    }

    // 定義具體的 AMCServiceFactory 類別
    public class AMCServiceFactory : SupplierServiceFactory
    {
        // 實現 GetCarInfomationService 方法  
        public ICarInfomationService GetCarInfomationService()
        {
            // 創建 AMCService 物件 
            return new AMCService();
        }
    }

    // 定義具體的 TeslaServiceFactory 類別
    public class TeslaServiceFactory : SupplierServiceFactory
    {
        // 實現 GetCarInfomationService 方法  
        public ICarInfomationService GetCarInfomationService()
        {
            // 創建 TeslaService 物件 
            return new TeslaService();
        }
    }

    // 定義客戶端類別
    public class Client
    {
        // 定義一個 SupplierServiceFactory 類型的變數
        private SupplierServiceFactory factory;

        // 定義一個 ICarInfomationService 類型的變數
        private ICarInfomationService service;

        // 定義一個建構子,接收一個 SupplierServiceFactory 類型的參數
        public Client(SupplierServiceFactory factory)
        {
            // 將參數賦值給變數
            this.factory = factory;
        }

        // 定義一個創建供應商服務的方法
        public void CreateSupplierService()
        {
            // 使用工廠物件創建供應商服務物件
            service = factory.GetCarInfomationService();
        }

        // 定義一個使用供應商服務的方法
        public void UseSupplierService()
        {
            // 使用供應商服務物件執行相關操作
            service.DoSomething();
        }

    }

    // 在主程式中測試
    public class Program
    {
        public static void Main(string[] args)
        {
            // 創建 VOLVOServiceFactory 物件
            SupplierServiceFactory volvoFactory = new VOLVOServiceFactory();
            // 創建 Client 物件,傳入 VOLVOServiceFactory 物件作為參數
            Client volvoClient = new Client(volvoFactory);

            // 呼叫創建供應商服務的方法
            volvoClient.CreateSupplierService();

            // 呼叫使用供應商服務的方法
            volvoClient.UseSupplierService();

            // 創建 AMCServiceFactory 物件
            SupplierServiceFactory amcFactory = new AMCServiceFactory();

            // 創建 Client 物件,傳入 AMCServiceFactory 物件作為參數
            Client amcClient = new Client(amcFactory);

            // 呼叫創建供應商服務的方法
            amcClient.CreateSupplierService();

            // 呼叫使用供應商服務的方法
            amcClient.UseSupplierService();

            // 創建 TeslaServiceFactory 物件
            SupplierServiceFactory teslaFactory = new TeslaServiceFactory();

            // 創建 Client 物件,傳入 TeslaServiceFactory 物件作為參數
            Client teslaClient = new Client(teslaFactory);

            // 呼叫創建供應商服務的方法
            teslaClient.CreateSupplierService();

            // 呼叫使用供應商服務的方法
            teslaClient.UseSupplierService();
        }
    }

可以看到從以上所提的元素作為切入,

Creator(創建者):SupplierServiceFactory 擔任Creator作用,並且定義了一個抽象的 GetCarInfomationService 方法。

ConcreteCreator(具體創建者):定義具體的 VOLVOServiceFactory、AMCServiceFactory 和 TeslaServiceFactory類別,
是SupplierServiceFactory 介面的具體實現。

Product(產品):ICarInfomationService

ConcreteProduct(具體產品):VOLVOService、AMCService、TeslaService...。

那麼最後可以看到,不論是簡單工廠或是工廠都可以透過傳入參數來做為調整,
這時候,
就會開始做一定量的調整,
讓程式能保有彈性的去切換。

如果以筆者的程式,
就會再次提起GetCarInfomationService。

public class SupplierServiceBuilder
{
    // ...

    public ICarInfomationService GetCarInfomationService(string local)
    {
        return GetServices(local);
    }

    private CarInfomationService GetServices(string pLocal)
    {
        CarInfomationService lHotelService = null;
		// ...

        // 根據提供的 pLocal 參數選擇要實例化的具體產品
		switch (enumReturn)
		{
			case EnumSupplierCode.VOLVO:
				lHotelService = new VOLVOService();
				break;
			case EnumSupplierCode.AMC:
				lHotelService = new AMCService();
				break;
			case EnumSupplierCode.Tesla:
				lHotelService = new TeslaService();
				break;
		}

        return lHotelService;
    }

    // ...
}

各位可以從之前所解說過的元素,
去找到對應的幾種形式。

而這當然不是最完善的狀態,
也可以根據之前所說做進一步的優化,
例如DI或是之前所說過的用其他方式等等。


上一篇
初階面試常見題目回答-簡單工廠模式-鐵人賽第十四日
下一篇
初階面試常見題目回答-抽象工廠模式-鐵人賽第十六日
系列文
初階面試常見題目彙整30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言