JavaRush /Java Blog /Random-TW /設計模式:抽象工廠

設計模式:抽象工廠

在 Random-TW 群組發布
你好!今天我們繼續學習設計模式,聊聊抽象工廠設計模式:AbstractFactory - 1講座期間我們將做什麼:
  • 讓我們來討論一下什麼是抽象工廠以及這個模式解決什麼問題;
  • 我們將創建一個跨平台應用程式的框架,用於透過使用者介面訂購咖啡;
  • 讓我們透過圖表和代碼來研究使用此模式的說明;
  • 作為獎勵,講座中隱藏了一個復活節彩蛋,透過它您將學習使用 Java 確定作業系統的名稱,並根據結果執行一個或另一個操作。
要完全理解此模式,您需要很好地理解以下主題:
  • Java中的繼承;
  • Java 中的抽象類別和方法。

抽象工廠模式解決了什麼問題?

與所有工廠模式一樣,抽象工廠幫助我們正確組織新物件的創建。在它的幫助下,我們可以管理各種互連物件系列的「發布」。各種相互關聯的物件系列...它是什麼?別擔心:其實一切都比看起來更簡單。讓我們從相關物件系列開始吧?假設你和我正在製定一個策略,其中有幾個戰鬥單元:
  • 步兵;
  • 騎兵;
  • 弓箭手。
這些類型的作戰單位彼此相關,因為它們在同一支軍隊中服役。我們可以說上面列出的類別是一系列相互關聯的物件。就這麼解決了 但抽象工廠模式用於組織各種互連物件系列的創建。這裡也沒什麼複雜的。讓我們繼續這個例子的策略。他們通常有幾個不同的對立面。不同方的作戰單位在外觀上可能有顯著差異。羅馬軍隊的步兵、騎兵和弓箭手與維京人的步兵、騎兵和弓箭手不一樣。在戰略框架內,不同軍隊的士兵是相互關聯的不同對象家族。如果因為程式設計師的錯誤,一名身穿拿破崙時代法國制服、手持步槍的士兵在羅馬步兵中走來走去,那就很有趣了。正是為了解決這樣的問題,需要抽象工廠設計模式。不,不是時間旅行的尷尬問題,而是創建各種相互關聯的物件群組的問題。抽象工廠提供了用於創建所有現有產品(系列物件)的介面。抽象工廠通常有多個實作。他們每個人都負責創建其中一種變體的產品。作為該策略的一部分,我們將擁有一個抽象工廠,用於創建抽象步兵、弓箭手和騎兵,以及該工廠的實現。一個製造羅馬軍團士兵的工廠,例如一個製造迦太基戰士的工廠。抽像是該模式最重要的原則。工廠客戶只能透過抽象介面來使用它和產品。因此,我們不必考慮目前正在創造什麼樣的戰士,而是將這個責任轉移到抽象工廠的某些具體實現。

我們持續實現咖啡店的自動化

上一講中,我們學習了工廠方法模式,借助它我們能夠擴展咖啡業務並開設幾個新的咖啡銷售點。今天,我們將繼續努力實現業務現代化。使用抽象工廠模式,我們將為在線訂購咖啡的新桌面應用程式奠定基礎。當我們為桌面編寫應用程式時,我們應該始終考慮跨平台。我們的應用程式應該可以在 macOS 和 Windows 上運行(劇透:Linux 將留給您作為家庭作業)。我們的應用程式會是什麼樣子?非常簡單:它將是一個由文字欄位、選擇欄位和按鈕組成的表單。如果您有使用不同作業系統的經驗,您一定會注意到 Windows 上的按鈕呈現方式與 Mac 上不同。就像其他一切一樣......所以,讓我們開始吧。正如您可能已經了解的那樣,在產品系列的角色中,我們將擁有圖形介面元素:
  • 紐扣;
  • 文字欄位;
  • 供選擇的欄位。
免責聲明。在每個介面中,我們可以定義諸如onClickonValueChanged或 之類的方法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 gui factory 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 gui factory 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 OrderCoffeeForm {
    private final TextField customerNameTextField;
    private final Select coffeTypeSelect;
    private final Button orderButton;

    public OrderCoffeeForm(GUIFactory factory) {
        System.out.println("Creating order coffee form");
        customerNameTextField = factory.createTextField();
        coffeTypeSelect = factory.createSelect();
        orderButton = factory.createButton();
    }
}
抽象工廠被傳遞給表單建構函數,該構造函數會建立介面元素。我們將所需的工廠實作傳遞給建構函數,以便我們可以為特定作業系統建立介面元素。
public class Application {
    private OrderCoffeeForm orderCoffeeForm;

    public void drawOrderCoffeeForm() {
        // Определим Name операционной системы, получив meaning системной проперти через System.getProperty
        String osName = System.getProperty("os.name").toLowerCase();
        GUIFactory guiFactory;

        if (osName.startsWith("win")) { // Для windows
            guiFactory = new WindowsGUIFactory();
        } else if (osName.startsWith("mac")) { // Для mac
            guiFactory = new MacGUIFactory();
        } else {
            System.out.println("Unknown OS, can't draw form :( ");
            return;
        }
        orderCoffeeForm = new OrderCoffeeForm(guiFactory);
    }

    public static void main(String[] args) {
        Application application = new Application();
        application.drawOrderCoffeeForm();
    }
}
如果我們在 Windows 上運行該應用程序,我們將得到以下輸出:

Creating gui factory for Windows OS
Creating order coffee form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
在 Mac 上,輸出如下:

Creating gui factory for macOS
Creating order coffee form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
在 Linux 上:

Unknown OS, can't draw form :( 
好吧,你和我得出以下結論。我們為 GUI 應用程式編寫了一個框架,該框架準確地創建了適合給定作業系統的介面元素。讓我們簡單地重複一下我們創建的內容:
  • 產品系列:輸入欄位、選擇欄位和按鈕。
  • 此系列產品的各種實現,適用於 Windows 和 macOS。
  • 一個抽象工廠,我們在其中定義了用於創建產品的介面。
  • 我們工廠的兩個實現,每個實現負責創建特定的產品系列。
  • 一個表單,一個 Java 類,其欄位是抽象介面元素,這些元素在建構函式中使用抽象工廠用所需的值進行初始化。
  • 應用類。在其中,我們建立一個表單,透過該表單將工廠所需的實作傳遞給建構函式。
Total:我們已經實作了抽象工廠模式。

抽象工廠:使用說明

抽象工廠是一種設計模式,用於管理不同產品系列的創建,而不依賴特定的產品類別。使用此範本時,您必須:
  1. 自行定義產品系列。假設我們有兩個:
    • SpecificProductA1,SpecificProductB1
    • SpecificProductA2,SpecificProductB2
  2. 對於該系列中的每個產品,定義一個抽象類別(介面)。在我們的例子中是:
    • ProductA
    • ProductB
  3. 在每個產品系列中,每個產品都必須實作步驟 2 中定義的介面。
  4. 建立一個抽象工廠,並為步驟 2 中定義的每個產品建立方法。在我們的例子中,這些方法將是:
    • ProductA createProductA();
    • ProductB createProductB();
  5. 創建抽象工廠的實現,以便每個實現控制同一系列產品的創建。為此,在抽象工廠的每個實作中,有必要實作所有創建方法,以便在其中創建並返回產品的具體實作。
下面是一個 UML 圖,說明了上述指令: 設計模式:AbstractFactory - 3現在讓我們來寫該指令的程式碼:
// Определим общие интерфейсы продуктов
public interface ProductA {}
public interface ProductB {}

// Создадим различные реализации (семейства) наших продуктов
public class SpecificProductA1 implements ProductA {}
public class SpecificProductB1 implements ProductB {}

public class SpecificProductA2 implements ProductA {}
public class SpecificProductB2 implements ProductB {}

// Создадим абстрактную фабрику
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// Создадим реализацию абстрактной фабрики для создания продуктов семейства 1
public class SpecificFactory1 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB1();
    }
}

// Создадим реализацию абстрактной фабрики для создания продуктов семейства 1
public class SpecificFactory2 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB2();
    }
}

家庭作業

要整合材料,您可以做兩件事:
  1. 改進咖啡訂購應用程序,使其可以在 Linux 上運行。
  2. 創建您自己的抽象工廠來生產任何策略的單元。這既可以是真實軍隊的歷史策略,也可以是獸人、矮人和精靈的幻想。最主要的是你覺得有趣。發揮創意,將圖釘發佈到控制台,並享受學習模式的樂趣!
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION