工厂模式
工厂模式中文讲解
工厂模式(Factory Pattern)是设计模式中创建型模式的一种,广泛用于面向对象编程中,特别是在需要灵活创建对象的场景。它的核心思想是将对象的创建过程封装起来,通过工厂类来控制对象的实例化,而不是直接使用 new
关键字。工厂模式可以提高代码的灵活性、可扩展性和可维护性,符合开闭原则(对扩展开放,对修改关闭)。
以下用中文详细讲解工厂模式的定义、分类、代码示例、应用场景、优缺点和注意事项。
1. 什么是工厂模式?
工厂模式是一种创建型设计模式,用于定义一个创建对象的接口或方法,但让子类或具体工厂决定实例化哪个具体类。它的核心是将对象的创建与使用分离,避免客户端直接依赖具体类。
- 问题:如果直接使用
new
创建对象,代码会与具体类耦合。当需求变化(如新增类或修改实现)时,需要修改客户端代码,违反开闭原则。 - 解决方案:引入一个工厂类或方法,负责对象的创建,客户端只与工厂接口交互,无需知道具体类的实现。
工厂模式有三种主要变体:
- 简单工厂模式(Simple Factory):非GoF的23种模式,但常作为入门。
- 工厂方法模式(Factory Method):GoF定义的经典模式。
- 抽象工厂模式(Abstract Factory):处理相关产品族的创建。
2. 工厂模式的分类及讲解
(1) 简单工厂模式(Simple Factory)
- 定义:由一个工厂类根据传入的参数决定创建哪种具体产品对象。
- 结构:
- 产品接口:定义产品的公共行为。
- 具体产品:实现产品接口的类。
- 工厂类:包含一个静态方法,根据参数创建具体产品。
- 适用场景:产品种类较少,创建逻辑简单。
代码示例:简单工厂模式
// 产品接口
interface Product {
void show();
}
// 具体产品A
class ProductA implements Product {
public void show() {
System.out.println("这是产品A");
}
}
// 具体产品B
class ProductB implements Product {
public void show() {
System.out.println("这是产品B");
}
}
// 简单工厂类
class SimpleFactory {
public static Product createProduct(String type) {
if ("A".equals(type)) {
return new ProductA();
} else if ("B".equals(type)) {
return new ProductB();
}
return null; // 无效类型
}
}
// 测试
public class SimpleFactoryTest {
public static void main(String[] args) {
Product product = SimpleFactory.createProduct("A");
if (product != null) {
product.show(); // 输出:这是产品A
}
product = SimpleFactory.createProduct("B");
if (product != null) {
product.show(); // 输出:这是产品B
}
}
}
说明:
- 客户端通过
SimpleFactory.createProduct("A")
创建对象,无需直接new ProductA()
。 - 缺点:新增产品(如
ProductC
)需修改工厂类,违反开闭原则。
(2) 工厂方法模式(Factory Method)
- 定义:定义一个创建产品的接口,让子类(具体工厂)决定实例化哪个具体产品。
- 结构:
- 抽象产品接口:定义产品行为。
- 具体产品:实现产品接口。
- 抽象工厂接口:声明工厂方法(如
createProduct()
)。 - 具体工厂:实现工厂方法,创建具体产品。
- 适用场景:需要扩展新产品,且不想修改现有代码。
代码示例:工厂方法模式
// 抽象产品接口
interface Product {
void show();
}
// 具体产品A
class ProductA implements Product {
public void show() {
System.out.println("这是产品A");
}
}
// 具体产品B
class ProductB implements Product {
public void show() {
System.out.println("这是产品B");
}
}
// 抽象工厂接口
interface Factory {
Product createProduct();
}
// 具体工厂A
class FactoryA implements Factory {
public Product createProduct() {
return new ProductA();
}
}
// 具体工厂B
class FactoryB implements Factory {
public Product createProduct() {
return new ProductB();
}
}
// 测试
public class FactoryMethodTest {
public static void main(String[] args) {
Factory factory = new FactoryA();
Product product = factory.createProduct();
product.show(); // 输出:这是产品A
factory = new FactoryB();
product = factory.createProduct();
product.show(); // 输出:这是产品B
}
}
说明:
- 每个产品对应一个具体工厂,新增产品(如
ProductC
)只需添加FactoryC
,无需修改现有工厂。 - 优点:符合开闭原则,扩展性强。
(3) 抽象工厂模式(Abstract Factory)
- 定义:提供一个接口,用于创建一系列相关或依赖的对象的家族,无需指定具体类。
- 结构:
- 抽象产品接口:多个产品接口(如按钮、文本框)。
- 具体产品:实现产品接口,属于不同家族(如 Windows 风格、Mac 风格)。
- 抽象工厂接口:声明创建多个产品的工厂方法。
- 具体工厂:为每个家族实现工厂方法。
- 适用场景:需要创建一组相关对象(如 UI 组件的不同风格)。
代码示例:抽象工厂模式
// 抽象产品接口1:按钮
interface Button {
void render();
}
// 抽象产品接口2:文本框
interface TextField {
void display();
}
// 具体产品:Windows按钮
class WindowsButton implements Button {
public void render() {
System.out.println("渲染Windows风格按钮");
}
}
// 具体产品:Windows文本框
class WindowsTextField implements TextField {
public void display() {
System.out.println("显示Windows风格文本框");
}
}
// 具体产品:Mac按钮
class MacButton implements Button {
public void render() {
System.out.println("渲染Mac风格按钮");
}
}
// 具体产品:Mac文本框
class MacTextField implements TextField {
public void display() {
System.out.println("显示Mac风格文本框");
}
}
// 抽象工厂接口
interface UIFactory {
Button createButton();
TextField createTextField();
}
// 具体工厂:Windows
class WindowsFactory implements UIFactory {
public Button createButton() {
return new WindowsButton();
}
public TextField createTextField() {
return new WindowsTextField();
}
}
// 具体工厂:Mac
class MacFactory implements UIFactory {
public Button createButton() {
return new MacButton();
}
public TextField createTextField() {
return new MacTextField();
}
}
// 测试
public class AbstractFactoryTest {
public static void main(String[] args) {
UIFactory factory = new WindowsFactory();
Button button = factory.createButton();
TextField textField = factory.createTextField();
button.render(); // 输出:渲染Windows风格按钮
textField.display(); // 输出:显示Windows风格文本框
factory = new MacFactory();
button = factory.createButton();
textField = factory.createTextField();
button.render(); // 输出:渲染Mac风格按钮
textField.display(); // 输出:显示Mac风格文本框
}
}
说明:
- 抽象工厂适合创建一组相关对象(如 Windows 风格的按钮和文本框)。
- 优点:保证产品家族一致性;缺点:新增产品类型需修改抽象工厂接口。
3. 工厂模式的应用场景
- 简单工厂:
- 产品种类固定,逻辑简单,如日志记录器(ConsoleLogger、FileLogger)。
- 客户端只关心产品使用,不关心创建细节。
- 工厂方法:
- 需要扩展新产品,如数据库连接(MySQLConnection、OracleConnection)。
- Spring 的
BeanFactory
是工厂方法的典型实现。
- 抽象工厂:
- 创建一组相关对象,如 GUI 框架(Windows/Mac 风格组件)。
- 跨平台应用(如不同操作系统下的文件系统操作)。
实际案例:
- Servlet 相关:在 Servlet 中,工厂模式可用于创建不同类型的处理器(如 XML/JSON 响应处理器)。
- Spring 框架:
ApplicationContext
使用工厂模式创建 Bean。 - JDBC:
DriverManager
使用工厂方法创建数据库连接。
4. 工厂模式的优缺点
优点:
- 解耦:客户端与具体产品类解耦,只依赖接口。
- 扩展性:工厂方法和抽象工厂支持新增产品,无需修改现有代码。
- 封装性:隐藏对象创建细节,简化客户端代码。
- 一致性:抽象工厂确保产品家族的一致性。
缺点:
- 复杂性:工厂模式引入额外类(如工厂类),增加代码量。
- 简单工厂局限:新增产品需修改工厂类,违反开闭原则。
- 抽象工厂扩展困难:新增产品类型需修改接口和所有具体工厂。
5. 注意事项
- 选择合适的工厂模式:
- 简单工厂适合简单场景,产品种类少。
- 工厂方法适合需要扩展的场景。
- 抽象工厂适合创建相关对象家族。
- 命名规范:
- 工厂类以
Factory
结尾(如ProductFactory
)。 - 方法名以
create
或get
开头(如createProduct
)。
- 中文编码问题:
- 如果产品涉及中文(如产品名称),确保使用 UTF-8 编码,避免乱码。
- 示例:
System.out.println("产品名称:" + URLEncoder.encode(name, "UTF-8"));
。
- 性能考虑:
- 避免频繁创建工厂对象,可用单例模式优化。
- 对于大量对象创建,考虑缓存或享元模式。
- 结合其他模式:
- 与单例模式结合:工厂类可以是单例。
- 与策略模式结合:根据上下文选择工厂。
- 常见问题解决:
- 类型错误:确保工厂方法返回的接口类型一致。
- 扩展困难:优先选择工厂方法或抽象工厂,避免简单工厂的修改问题。
6. 与 Servlet 的结合
在 Servlet 开发中,工厂模式常用于:
- 动态处理请求:根据请求参数创建不同处理器。
interface RequestHandler {
void handle(HttpServletRequest req, HttpServletResponse resp) throws IOException;
}
class JsonHandler implements RequestHandler {
public void handle(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setContentType("application/json;charset=UTF-8");
resp.getWriter().write("{\"message\": \"JSON响应\"}");
}
}
class Factory {
public static RequestHandler createHandler(String type) {
if ("json".equals(type)) {
return new JsonHandler();
}
return null;
}
}
public class MyServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String type = req.getParameter("type");
RequestHandler handler = Factory.createHandler(type);
if (handler != null) {
handler.handle(req, resp);
} else {
resp.getWriter().write("无效类型");
}
}
}
- 配置管理:工厂模式创建不同配置的数据库连接或服务。
7. 总结
- 工厂模式通过封装对象创建过程,提高代码灵活性和可扩展性。
- 简单工厂简单但扩展性差;工厂方法符合开闭原则;抽象工厂适合产品家族。
- 在 Servlet 中,工厂模式可用于动态处理请求或服务创建。
- 掌握工厂模式的核心思想(创建与使用的分离),结合实际场景选择合适变体。
如果需要更深入的讲解(如抽象工厂的复杂场景)、更多 Servlet 示例,或与其他模式(如单例、策略)的对比,请告诉我!