你好!今天我们继续学习设计模式,聊聊抽象工厂。 讲座期间我们将做什么:
- 我们来讨论一下什么是抽象工厂以及这个模式解决什么问题;
- 我们将创建一个跨平台应用程序的框架,用于通过用户界面订购咖啡;
- 让我们通过图表和代码来研究使用此模式的说明;
- 作为奖励,讲座中隐藏了一个复活节彩蛋,通过它您将学习使用 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 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 类,其字段是抽象接口元素,这些元素在构造函数中使用抽象工厂用所需的值进行初始化。
- 应用类。在其中,我们创建一个表单,通过该表单将工厂所需的实现传递给构造函数。
抽象工厂:使用说明
抽象工厂是一种设计模式,用于管理不同产品系列的创建,而不依赖于特定的产品类别。使用此模板时,您必须:- 自行定义产品系列。假设我们有两个:
SpecificProductA1
,SpecificProductB1
SpecificProductA2
,SpecificProductB2
- 对于该系列中的每个产品,定义一个抽象类(接口)。在我们的例子中是:
ProductA
ProductB
- 在每个产品系列中,每个产品都必须实现步骤 2 中定义的接口。
- 创建一个抽象工厂,并为步骤 2 中定义的每个产品创建方法。在我们的例子中,这些方法将是:
ProductA createProductA();
ProductB createProductB();
- 创建抽象工厂的实现,以便每个实现控制同一系列产品的创建。为此,在抽象工厂的每个实现中,有必要实现所有创建方法,以便在其中创建并返回产品的具体实现。
// Определим общие интерфейсы продуктов
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();
}
}
家庭作业
要整合材料,您可以做两件事:- 改进咖啡订购应用程序,使其可以在 Linux 上运行。
- 创建您自己的抽象工厂来生产任何策略的单元。这既可以是真实军队的历史策略,也可以是兽人、矮人和精灵的幻想。最主要的是你觉得有趣。发挥创意,将图钉发布到控制台,并享受学习模式的乐趣!
GO TO FULL VERSION