在說完簡單工廠模式,
這時候就來說說工廠方法模式(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或是之前所說過的用其他方式等等。