工厂方法模式
在基类中定义工厂方法,并让子类决定要创建哪种产品
工厂方法模式 是 CoddyKit 上的免费 Java Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。
工厂方法的意图
工厂方法定义了用于创建对象的接口,但将决定实例化哪个类的责任交给子类。它将创建逻辑与客户端代码解耦。
没有工厂方法时的问题
没有工厂时,客户端代码中会充斥着 new ConcreteClass() 调用。添加新变体意味着必须修改每个调用位置——这违反了开闭原则。
// Client knows too much:
Shape shape;
if (type.equals("circle")) shape = new Circle(r);
else if (type.equals("rect")) shape = new Rectangle(w, h);
// Every new shape requires editing this code.创建者抽象类
请定义一个抽象创建者类,并在其中声明 createProduct() 工厂方法。子类重写该方法,以返回特定的产品类型。
public abstract class Dialog {
public void render() {
Button btn = createButton(); // factory method
btn.onClick();
}
protected abstract Button createButton();
}具体创建者
每个子类都重写工厂方法,以返回适当的产品,同时无需修改基类中的外围算法。
public class WindowsDialog extends Dialog {
@Override
protected Button createButton() { return new WindowsButton(); }
}
public class WebDialog extends Dialog {
@Override
protected Button createButton() { return new HtmlButton(); }
}产品接口
所有具体产品都实现同一个公共接口,这样创建者就能以通用方式使用它们。
public interface Button {
void onClick();
void render();
}
public class WindowsButton implements Button {
public void onClick() { System.out.println("Windows click"); }
public void render() { System.out.println("Render Windows button"); }
}静态工厂方法与工厂方法模式
静态工厂方法(例如 LocalDate.of())是一种命名约定,而不是 GoF 模式。GoF 模式使用继承;静态工厂则在单个类上使用静态方法。
// Static factory (NOT the GoF pattern)
LocalDate d = LocalDate.of(2024, 6, 15);
// GoF Factory Method uses a class hierarchy参数化工厂方法
向工厂方法传入参数,即可在多个产品之间进行选择,而无需为每种产品都创建一个子类。
public class ShapeFactory {
public static Shape create(String type, double... dims) {
return switch (type) {
case "circle" -> new Circle(dims[0]);
case "rectangle" -> new Rectangle(dims[0], dims[1]);
default -> throw new IllegalArgumentException("Unknown: " + type);
};
}
}使用泛型的工厂方法
使用泛型可以让工厂方法具备类型安全,并能在不同的产品族之间复用。
public abstract class Repository<T, ID> {
public abstract T findById(ID id);
protected abstract T createEmpty(); // factory method
}使用 Map 注册工厂
基于注册表的工厂会将类型字符串映射到 Supplier lambda,从而避免使用 if-else 链,并使注册过程具有动态性。
Map<String, Supplier<Notification>> registry = new HashMap<>();
registry.put("email", EmailNotification::new);
registry.put("sms", SmsNotification::new);
Notification n = registry.getOrDefault(type, DefaultNotification::new).get();工厂方法与抽象工厂
工厂方法通过继承创建一种产品类型。抽象工厂通过组合创建一组相关产品。当只有一种产品会发生变化时,请使用工厂方法;当整套产品需要一起变化时,请使用抽象工厂。
现实示例:Logger 工厂
SLF4J 的 LoggerFactory.getLogger(Class) 是一个静态工厂,它会返回正确的日志记录器实现(Logback、Log4j 或 JUL),而调用方无需知道具体是哪一种实现。
Logger log = LoggerFactory.getLogger(MyService.class);
log.info("Service started");快速检查
工厂方法模式的关键特征是什么?
回顾
工厂方法将实例化决策放入可重写的子类方法中,从而把对象创建与客户端解耦。当一个类无法预先确定需要创建哪些对象时,请使用它。
常见问题解答
「工厂方法模式」课时是免费的吗?
是的 — 「工厂方法模式」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。
「工厂方法模式」这节课中我会学到什么?
在基类中定义工厂方法,并让子类决定要创建哪种产品 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Java Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「工厂方法模式」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Java Academy 课中编写并运行代码吗?
能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。