你好!今天我們繼續研究設計模式,我們將討論抽象工廠模式。 以下是我們將在課程中介紹的內容:
- 我們將討論什麼是抽象工廠以及這種模式解決了什麼問題
- 我們將創建跨平台應用程序的框架,用於通過用戶界面訂購咖啡
- 我們將研究如何使用此模式的說明,包括查看圖表和代碼
- 作為獎勵,本課程包含一個隱藏的彩蛋,它將幫助您學習如何使用 Java 確定操作系統的名稱,並根據結果執行一個或另一個操作。
- Java中的繼承
- Java 中的抽像類和方法
抽象工廠解決什麼問題?
像所有工廠模式一樣,抽象工廠幫助我們確保正確創建新對象。我們用它來管理各種互連對象系列的“生產”。各種相互關聯的對象系列......這是什麼意思?別擔心:在實踐中,一切都比看起來簡單。首先,相互關聯的對象家族可能是什麼?假設我們正在製定一項涉及多種類型單位的軍事戰略:- 步兵
- 騎兵
- 弓箭手
讓我們繼續自動化我們的咖啡店
在上一課,我們研究了工廠方法模式。我們用它來擴展我們的咖啡業務並開設了幾個新地點。今天,我們將繼續實現業務現代化。使用抽象工廠模式,我們將為在線訂購咖啡的新桌面應用程序奠定基礎。在編寫桌面應用程序時,我們應該始終考慮跨平台支持。我們的應用程序必須同時在 macOS 和 Windows 上運行(劇透:對 Linux 的支持留給您作為家庭作業來實現)。我們的應用程序會是什麼樣子?非常簡單:它將是一個由文本字段、選擇字段和按鈕組成的表單。如果您有使用不同操作系統的經驗,您肯定會注意到 Windows 上的按鈕呈現方式與 Mac 上的不同。和其他一切一樣……好吧,讓我們開始吧。- 鈕扣
- 文本域
- 選擇字段
onClick
、onValueChanged
或 之類的方法onInputChanged
。換句話說,我們可以定義允許我們處理各種事件的方法(按下按鈕、輸入文本、在選擇框中選擇一個值)。這里特意省略了所有這些,以免示例過載並在我們研究工廠模式時使其更加清晰。讓我們為我們的產品定義抽象接口:
public interface Button {}
public interface Select {}
public interface TextField {}
對於每個操作系統,我們必須創建操作系統風格的界面元素。我們將為 Windows 和 MacOS 編寫代碼。讓我們為 Windows 創建實現:
public class WindowsButton implements Button {
}
public class WindowsSelect implements Select {
}
public class WindowsTextField implements TextField {
}
現在我們對 MacOS 做同樣的事情:
public class MacButton implements Button {
}
public class MacSelect implements Select {
}
public class MacTextField implements TextField {
}
出色的。現在我們可以繼續我們的抽象工廠,它將創建所有可用的抽象產品類型:
public interface GUIFactory {
Button createButton();
TextField createTextField();
Select createSelect();
}
高超。如您所見,我們還沒有做任何復雜的事情。接下來的一切也很簡單。通過類比產品,我們為每個操作系統創建各種工廠實現。讓我們從 Windows 開始:
public class WindowsGUIFactory implements GUIFactory {
public WindowsGUIFactory() {
System.out.println("Creating GUIFactory for Windows OS");
}
public Button createButton() {
System.out.println("Creating Button for Windows OS");
return new WindowsButton();
}
public TextField createTextField() {
System.out.println("Creating TextField for Windows OS");
return new WindowsTextField();
}
public Select createSelect() {
System.out.println("Creating Select for Windows OS");
return new WindowsSelect();
}
}
我們在方法和構造函數中添加了一些控制台輸出,以進一步說明正在發生的事情。現在對於 macOS:
public class MacGUIFactory implements GUIFactory {
public MacGUIFactory() {
System.out.println("Creating GUIFactory for macOS");
}
@Override
public Button createButton() {
System.out.println("Creating Button for macOS");
return new MacButton();
}
@Override
public TextField createTextField() {
System.out.println("Creating TextField for macOS");
return new MacTextField();
}
@Override
public Select createSelect() {
System.out.println("Creating Select for macOS");
return new MacSelect();
}
}
請注意,每個方法簽名都表明該方法返回一個抽像類型。但在方法內部,我們正在創建產品的特定實現。這是我們控制特定實例創建的唯一地方。現在是時候為表單編寫一個類了。這是一個 Java 類,其字段是接口元素:
public class CoffeeOrderForm {
private final TextField customerNameTextField;
private final Select coffeeTypeSelect;
private final Button orderButton;
public CoffeeOrderForm(GUIFactory factory) {
System.out.println("Creating coffee order form");
customerNameTextField = factory.createTextField();
coffeeTypeSelect = factory.createSelect();
orderButton = factory.createButton();
}
}
創建界面元素的抽象工廠被傳遞給表單的構造函數。我們會將必要的工廠實現傳遞給構造函數,以便為特定操作系統創建界面元素。
public class Application {
private CoffeeOrderForm coffeeOrderForm;
public void drawCoffeeOrderForm() {
// Determine the name of the operating system through System.getProperty()
String osName = System.getProperty("os.name").toLowerCase();
GUIFactory guiFactory;
if (osName.startsWith("win")) { // For Windows
guiFactory = new WindowsGUIFactory();
} else if (osName.startsWith("mac")) { // For Mac
guiFactory = new MacGUIFactory();
} else {
System.out.println("Unknown OS. Unable to draw form :(");
return;
}
coffeeOrderForm = new CoffeeOrderForm(guiFactory);
}
public static void main(String[] args) {
Application application = new Application();
application.drawCoffeeOrderForm();
}
}
如果我們在 Windows 上運行該應用程序,我們會得到以下輸出:
Creating GUIFactory for Windows OS
Creating coffee order form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
在 Mac 上,輸出將如下所示:
Creating GUIFactory for macOS
Creating coffee order form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
在 Linux 上:
Unknown OS. Unable to draw form :(
現在我們總結一下。我們編寫了一個基於 GUI 的應用程序的框架,其中的界面元素是專門為相關操作系統創建的。我們將簡潔地重複我們創建的內容:
- 由輸入字段、選擇字段和按鈕組成的產品系列。
- 適用於 Windows 和 macOS 的產品系列的不同實現。
- 定義用於創建我們產品的接口的抽象工廠。
- 我們工廠的兩個實現,每個負責創建一個特定的產品系列。
- 一種表單(Java 類),其字段是抽象接口元素,使用抽象工廠在構造函數中使用必要的值進行初始化。
- 應用程序類 在這個類中,我們創建一個表單,將所需的工廠實現傳遞給它的構造函數。
抽象工廠:如何使用
抽象工廠是一種設計模式,用於管理各種產品系列的創建,而無需綁定到具體的產品類。使用此模式時,您必須:- 定義產品系列。假設我們有兩個:
SpecificProductA1
,SpecificProductB1
SpecificProductA2
,SpecificProductB2
- 對於系列中的每個產品,定義一個抽像類(接口)。在我們的例子中,我們有:
ProductA
ProductB
- 在每個產品系列中,每個產品都必須實現步驟 2 中定義的接口。
- 創建一個抽象工廠,其中包含用於創建步驟 2 中定義的每個產品的方法。在我們的例子中,這些方法將是:
ProductA createProductA();
ProductB createProductB();
- 創建抽象工廠實現,以便每個實現控制單個系列產品的創建。為此,在抽象工廠的每個實現中,您需要實現所有創建方法,以便它們創建並返回特定的產品實現。
// Define common product interfaces
public interface ProductA {}
public interface ProductB {}
// Create various implementations (families) of our products
public class SpecificProductA1 implements ProductA {}
public class SpecificProductB1 implements ProductB {}
public class SpecificProductA2 implements ProductA {}
public class SpecificProductB2 implements ProductB {}
// Create an abstract factory
public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// Implement the abstract factory in order to create products in family 1
public class SpecificFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new SpecificProductA1();
}
@Override
public ProductB createProductB() {
return new SpecificProductB1();
}
}
// Implement the abstract factory in order to create products in family 2
public class SpecificFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new SpecificProductA2();
}
@Override
public ProductB createProductB() {
return new SpecificProductB2();
}
}
家庭作業
要加固材料,您可以做兩件事:- 改進咖啡訂購應用程序,使其也可以在 Linux 上運行。
- 創建您自己的抽象工廠,用於生產參與任何軍事戰略的單位。這可以是涉及真實軍隊的歷史軍事戰略,也可以是涉及獸人、侏儒和精靈的幻想戰略。重要的是選擇你感興趣的東西。發揮創意,在控制台上打印消息,並享受學習模式的樂趣!
GO TO FULL VERSION