什么是工厂方法模式
工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类中进行,从而将对象的创建与使用过程分离,使系统更加灵活。
为什么需要工厂方法模式
当一个类不知道它所必须创建的对象的类时,或者一个类希望由其子类来指定它所创建的对象时,工厂方法模式就派上了用场。例如,一个跨平台的UI框架需要创建不同操作系统下的按钮控件,但具体创建哪种按钮取决于运行环境。
工厂方法模式解决了"在不指定具体类的情况下创建对象"的问题。
工厂方法模式的核心实现
// 产品接口
public interface Product {
void operation();
}
// 具体产品A
public class ConcreteProductA implements Product {
@Override
public void operation() {
System.out.println("产品A的操作");
}
}
// 具体产品B
public class ConcreteProductB implements Product {
@Override
public void operation() {
System.out.println("产品B的操作");
}
}
// 创建者接口
public abstract class Creator {
// 工厂方法
public abstract Product createProduct();
// 某些使用产品的操作
public void someOperation() {
// 调用工厂方法创建产品
Product product = createProduct();
// 使用产品
product.operation();
}
}
// 具体创建者A
public class ConcreteCreatorA extends Creator {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// 具体创建者B
public class ConcreteCreatorB extends Creator {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
工厂方法模式的关键点
- 产品接口:定义工厂方法所创建的对象的接口
- 具体产品:实现产品接口的具体类
- 创建者接口/抽象类:声明工厂方法,返回产品类型的对象
- 具体创建者:重写工厂方法以返回特定的产品实例
实际应用示例:物流运输系统
下面通过一个物流运输系统的例子来展示工厂方法模式的应用:
// 运输工具接口
public interface Transport {
void deliver(String goods);
}
// 卡车运输
public class Truck implements Transport {
@Override
public void deliver(String goods) {
System.out.println("通过卡车运输" + goods + ",走陆路");
}
}
// 轮船运输
public class Ship implements Transport {
@Override
public void deliver(String goods) {
System.out.println("通过轮船运输" + goods + ",走水路");
}
}
// 飞机运输
public class Airplane implements Transport {
@Override
public void deliver(String goods) {
System.out.println("通过飞机运输" + goods + ",走空路");
}
}
// 物流抽象类
public abstract class Logistics {
// 工厂方法
public abstract Transport createTransport();
// 规划运输
public void planDelivery(String goods) {
System.out.println("开始规划运输...");
// 通过工厂方法创建运输工具
Transport transport = createTransport();
System.out.println("安排货物装载...");
// 使用运输工具
transport.deliver(goods);
System.out.println("运输完成!");
}
}
// 公路物流
public class RoadLogistics extends Logistics {
@Override
public Transport createTransport() {
return new Truck();
}
}
// 海运物流
public class SeaLogistics extends Logistics {
@Override
public Transport createTransport() {
return new Ship();
}
}
// 空运物流
public class AirLogistics extends Logistics {
@Override
public Transport createTransport() {
return new Airplane();
}
}
如何使用工厂方法模式
public class LogisticsDemo {
public static void main(String[] args) {
// 客户端代码
System.out.println("======= 运输电子产品 =======");
// 根据距离、成本等因素选择物流方式
Logistics logistics;
String transportType = "air"; // 可能来自配置或用户选择
// 根据运输类型选择具体的物流类
if (transportType.equals("road")) {
logistics = new RoadLogistics();
} else if (transportType.equals("sea")) {
logistics = new SeaLogistics();
} else {
logistics = new AirLogistics();
}
// 使用选定的物流安排运输
// 注意客户端代码只与抽象类交互,不直接使用具体产品类
logistics.planDelivery("智能手机100部");
System.out.println("\n======= 运输食品 =======");
// 更换物流方式
logistics = new RoadLogistics();
logistics.planDelivery("新鲜水果10吨");
}
}
运行结果
======= 运输电子产品 =======
开始规划运输...
安排货物装载...
通过飞机运输智能手机100部,走空路
运输完成!
======= 运输食品 =======
开始规划运输...
安排货物装载...
通过卡车运输新鲜水果10吨,走陆路
运输完成!
工厂方法模式的常见应用场景
- GUI框架:不同操作系统下创建不同外观的控件
- 数据库连接器:支持多种数据库系统
- 多格式文件解析器:处理不同格式的文件
- 支付系统:集成多种支付方式
- 日志记录框架:支持多种日志输出方式
- 跨平台应用:适配不同平台的功能实现
- 游戏角色创建:生成不同类型的游戏角色
工厂方法模式的优点
- 单一职责原则:将产品创建代码与使用代码分离
- 开闭原则:可以引入新产品而无需修改现有代码
- 灵活性:客户端代码与具体产品类解耦
- 可测试性:便于对产品进行单元测试
工厂方法模式的缺点
- 类爆炸:每增加一种产品,就需要增加一个具体工厂类
- 复杂度增加:引入了额外的抽象层次
- 继承限制:工厂角色通常由子类实现,不适合需要组合而非继承的场景
工厂方法与简单工厂的区别
简单工厂将所有产品的创建集中在一个工厂类中,通过条件判断创建不同产品:
public class SimpleFactory {
public static Transport createTransport(String type) {
if (type.equals("truck")) {
return new Truck();
} else if (type.equals("ship")) {
return new Ship();
} else if (type.equals("airplane")) {
return new Airplane();
}
throw new IllegalArgumentException("未知运输类型");
}
}
而工厂方法模式将产品创建委托给子类,更符合开闭原则,但需要创建更多类。
工厂方法模式小结
工厂方法模式通过将对象的创建延迟到子类进行,实现了创建与使用的分离。它适用于当一个类无法预知它所必须创建的对象的类,或希望由子类来指定创建的对象的情况。
这种模式在现代框架和库中被广泛使用,理解工厂方法模式有助于我们设计出更灵活、可维护的代码。在面向对象编程中,工厂方法是最基本也是最常用的设计模式之一。


被折叠的 条评论
为什么被折叠?



