工厂模式
本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 66 课,共 87 课。
工厂模式是一种创建型设计模式,它将对象创建委托给单独的方法或类。你不必在代码中直接使用 new,而是让工厂为你创建对象。当你有多个共享同一接口或父类的相关类时,这种模式尤其有用。
设想一个可以发送电子邮件、SMS 或推送通知的通知系统。如果没有工厂,你的代码就需要了解每个具体类:
// 不使用工厂时,客户端必须知道所有具体类
Notification notification;
if (type.equals("email")) {
notification = new EmailNotification();
} else if (type.equals("sms")) {
notification = new SMSNotification();
}使用工厂模式,可以集中管理创建逻辑:
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
public void send(String message) {
System.out.println("Email: " + message);
}
}
public class SMSNotification implements Notification {
public void send(String message) {
System.out.println("SMS: " + message);
}
}
public class NotificationFactory {
public static Notification create(String type) {
if (type.equals("email")) {
return new EmailNotification();
} else if (type.equals("sms")) {
return new SMSNotification();
}
return null;
}
}现在客户端代码更简洁了,也不依赖具体类:
Notification notification = NotificationFactory.create("email");
notification.send("Hello!"); // 输出:Email: Hello!主要优势在于,添加新的通知类型只需要更新工厂:客户端代码保持不变。这遵循面向接口编程的原则,让你的系统更灵活,也更容易扩展。
挑战
简单让我们使用工厂模式构建一个图形绘制系统!你不用在代码中到处直接创建图形对象,而是将创建逻辑集中到一个工厂中,由它根据简单的字符串标识符创建不同类型的图形。
你将把代码分成 4 个文件:
Shape.java:定义一个名为Shape的接口,作为所有图形的通用约定。接口应声明一个draw()方法,该方法不返回任何内容,只打印正在绘制的图形信息。Shapes.java:创建 3 个实现Shape接口的类:Circle:它的draw()方法应打印Drawing a CircleRectangle:它的draw()方法应打印Drawing a RectangleTriangle:它的draw()方法应打印Drawing a TriangleShapeFactory.java:创建负责处理图形创建的工厂类。你的ShapeFactory应有一个静态方法createShape(String type),该方法返回一个Shape。根据参数 type:- 如果 type 等于
"circle",则返回一个新的Circle - 如果 type 等于
"rectangle",则返回一个新的Rectangle - 如果 type 等于
"triangle",则返回一个新的Triangle - 对于其他任何值,返回
null
- 如果 type 等于
Main.java:将工厂系统组合起来!你会收到两个输入:两个图形类型(都是字符串)。对于每个输入,使用
ShapeFactory创建图形,并将其存储在一个Shape变量中。如果工厂返回有效的图形(不是 null),就调用它的draw()方法。如果返回 null,就打印Unknown shape: [type],其中 [type] 是提供的输入。按顺序处理两个输入,每个输入的输出各占一行。
你会按顺序收到两个输入:第一个图形类型(字符串)和第二个图形类型(字符串)。
注意,Main 类从不直接使用 new Circle() 或 new Rectangle()。它只了解 Shape 接口,并请求工厂创建对象。这就是工厂模式的强大之处:客户端代码与具体类解耦了!
亲手试试
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取两种形状类型
String type1 = scanner.nextLine();
String type2 = scanner.nextLine();
// TODO:使用 ShapeFactory 创建第一个形状
// 如果形状不为 null,就调用 draw()
// 如果形状为 null,就打印 "Unknown shape: [type]"
// TODO:对第二个形状执行相同操作
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Java 在线编译器