你好!今天我们继续研究设计模式,我们将讨论抽象工厂模式。
以下是我们将在课程中介绍的内容:
现在我们将根据这些指令编写代码:

- 我们将讨论什么是抽象工厂以及这种模式解决了什么问题
- 我们将创建跨平台应用程序的框架,用于通过用户界面订购咖啡
- 我们将研究如何使用此模式的说明,包括查看图表和代码
- 作为奖励,本课程包含一个隐藏的彩蛋,它将帮助您学习如何使用 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