此時,您可能已經遇到了設計模式。例如,單例

讓我們回顧一下模式是什麼,為什麼需要它們,以及創建模式是什麼(單例就是一個例子)。我們還將研究一種新模式:工廠方法。

在軟件開發中,設計模式是一種可重複的架構構造,表示在某些重複出現的上下文中對設計問題的解決方案。

通常,模式不是可以直接轉換為代碼的最終解決方案。它只是可以在各種情況下使用的問題的模型解決方案。

創建型模式是處理對象創建過程的設計模式。它們使創建一個獨立於用於創建、組合和呈現對象的方法的系統成為可能。

工廠方法是一種創建型設計模式,它定義了一個用於在父類中創建對象的通用接口,使其後代能夠創建這些對象。在創建時,後代可以確定創建哪個類。

該模式解決了什麼問題?

想像一下,您決定創建一個交付程序。最初,您將僱用帶汽車的快遞員並使用對象代表程序中的運載工具。快遞員將包裹從 A 點運送到 B 點,依此類推。十分簡單。

該計劃越來越受歡迎。您的業務正在增長,您希望擴展到新市場。例如,您也可以開始運送食品和運輸貨物。在這種情況下,可以通過快遞員步行、滑板車和自行車來運送食物,但貨運需要卡車。

現在您需要跟踪幾件事(何時、向誰、什麼以及多少),包括每個快遞員可以攜帶多少。新的交通方式具有不同的速度和容量。然後你注意到你程序中的大多數實體都與班級。您意識到,為了使您的程序適用於其他交付方式,您將不得不重寫現有的代碼庫,並且在每次添加新車輛時都需要重新編寫。

結果是可怕的代碼充滿了條件語句,這些語句根據運輸類型執行不同的操作。

解決方案

工廠方法模式建議通過調用特殊的工廠方法而不是直接使用new運算符來創建對象。具有工廠方法的類的子類可以修改特定車輛的創建對象。乍一看,這似乎毫無意義:我們只是將構造函數調用從程序中的一個位置移動到另一個位置。但是現在您可以覆蓋子類中的工廠方法來更改正在創建的運輸類型。

讓我們看一下這種方法的類圖:

為了讓這個系統工作,所有返回的對像都必須有一個公共接口。子類將能夠生成實現此接口的不同類的對象。

例如,TruckCar類使用deliver方法實現CourierTransport接口。這些類中的每一個都以不同的方式實現該方法:卡車運送貨物,而汽車運送食物、包裹等。TruckCreator類中的工廠方法返回卡車對象,CarCreator類返回汽車對象。

對於工廠方法的客戶端,這些對象之間沒有區別,因為它會將它們視為某種抽象的CourierTransport。客戶會非常關心該對像是否具有交付方法,但該方法究竟如何工作並不重要。

Java中的實現:


public interface CourierTransport {
	void deliver();
}
public class Car implements CourierTransport {
	@Override
	public void deliver() {
    		System.out.println("The package is being delivered by car");
	}
}
public class Truck implements CourierTransport {
	@Override
	public void deliver() {
    		System.out.println("The freight is being delivered by truck");
	}
}
public abstract class CourierTransportCreator {
	public abstract CourierTransport createTransport();
}
public class CarCreator extends CourierTransportCreator {
	@Override
	public CourierTransport createTransport() {
    		return new Car();
	}
}
public class TruckCreator extends CourierTransportCreator {
	@Override
	public CourierTransport createTransport() {
    		return new Truck();
	}
}
 
public class Delivery {
	private String address;
	private CourierTransport courierTransport;
 
	public void Delivery() {
	}
 
	public Delivery(String address, CourierTransport courierTransport) {
    	this.address = address;
    	this.courierTransport = courierTransport;
	}
 
	public CourierTransport getCourierTransport() {
    		return courierTransport;
	}
 
	public void setCourierTransport(CourierTransport courierTransport) {
    		this.courierTransport = courierTransport;
	}
 
	public String getAddress() {
    		return address;
	}
 
	public void setAddress(String address) {
    		this.address = address;
	}
}
public static void main(String[] args) {
    	// Accept a new type of order from the database (pseudocode)
    	String type = database.getTypeOfDeliver();
 
    	Delivery delivery = new Delivery();
    	
    	// Set the transport for delivery
        delivery.setCourierTransport(getCourierTransportByType(type));
    	
    	// Make the delivery
        delivery.getCourierTransport().deliver();
 
	}
 
	public static CourierTransport getCourierTransportByType(String type) {
    	switch (type) {
        	case "CarDelivery":
            	return new CarCreator().createTransport();
        	case "TruckDelivery":
            	return new TruckCreator().createTransport();
        	default:
            	throw new RuntimeException();
	    }
	}
    

如果我們想創建一個新的交付對象,那麼程序會自動創建一個合適的運輸對象。

我們什麼時候應該應用這種模式?

1. 當您事先不知道您的代碼需要處理的對象的類型和依賴性時。

工廠方法將生成交通工具的代碼與使用交通工具的代碼分開。因此,可以在不觸及其餘代碼的情況下擴展用於創建對象的代碼。

例如,要添加對新型交通工具的支持,您需要創建一個新的子類並在其中定義一個返回新交通工具實例的工廠方法。

2. 當您想通過重用現有對象而不是創建新對象來節省系統資源時。

當使用資源密集型對象(如數據庫連接、文件系統等)時,通常會出現此問題。

想一想重用現有對象需要採取的步驟:

  1. 首先,您需要創建一個共享存儲庫來存儲您創建的所有對象。

  2. 請求新對象時,您需要查看存儲庫並檢查它是否包含可用對象。

  3. 將對象返回給客戶端代碼。

  4. 但是,如果沒有可用對象,請創建一個新對象並將其添加到存儲庫中。

所有這些代碼都需要放在不會弄亂客戶端代碼的地方。最方便的地方是構造函數,因為我們只需要在創建對象時進行所有這些檢查。las,構造函數總是創建一個新對象——它不能返回一個現有對象。

這意味著需要另一種方法來返回現有對象和新對象。這將是工廠方法。

3. 當您希望允許用戶擴展您的框架或庫的某些部分時。

用戶可以通過繼承來擴展你的框架類。但是如何讓框架創建這些新類的對象而不是標準類的對象呢?

解決方案是讓用戶不僅可以擴展組件,還可以擴展創建這些組件的類。為此,創建類必須具有可以定義的特定創建方法。

優點

  • 將一個類與特定的運輸類分離。
  • 將創建交通工具的代碼保存在一個地方,使代碼更易於維護。
  • 簡化向程序中添加新交通方式的過程。
  • 貫徹開閉原則。

缺點

可能導致大型並行類層次結構,因為每個產品類都必須有自己的創建者子類。

讓我們總結一下

您了解了工廠方法模式並看到了一種可能的實現。這種模式經常用於各種庫中,這些庫提供用於創建其他對象的對象。

當您想要輕鬆地添加現有類的子類的新對像以便與您的主要業務邏輯交互並且不會由於不同的上下文而使您的代碼膨脹時,請使用工廠方法模式。