目录
一、从实际场景理解工厂方法模式
为了让大家更直观地理解工厂方法模式,我们来看看在物流管理系统中的应用场景。假设我们正在开发一个简单的物流管理系统,最初,系统只支持卡车运输这一种运输方式 。在代码实现上,我们可能会有一个Truck类来表示卡车运输:
// 卡车运输类
class Truck {
public void deliver() {
System.out.println("货物通过卡车运输");
}
}
在物流管理的核心业务代码中,我们会直接创建Truck对象来进行运输操作:
public class Logistics {
public static void main(String[] args) {
Truck truck = new Truck();
truck.deliver();
}
}
随着业务的发展,海运公司希望我们的系统能够支持海上运输。这时候,如果不使用设计模式,我们需要修改大量的现有代码。首先,我们要创建一个Ship类来表示轮船运输:
// 轮船运输类
class Ship {
public void deliver() {
System.out.println("货物通过轮船运输");
}
}
然后,在物流管理的业务代码中,我们需要根据不同的运输需求,添加条件判断来创建不同的运输对象:
public class Logistics {
public static void main(String[] args) {
// 假设通过一个标志来决定运输方式,1代表卡车,2代表轮船
int shippingMethod = 2;
if (shippingMethod == 1) {
Truck truck = new Truck();
truck.deliver();
} else if (shippingMethod == 2) {
Ship ship = new Ship();
ship.deliver();
}
}
}
这样做的问题很明显:代码的耦合度非常高。如果后续再添加新的运输方式,比如航空运输,我们就需要再次修改Logistics类中的业务逻辑代码,这违反了软件开发中的开闭原则(对扩展开放,对修改关闭)。而且,当运输方式越来越多,Logistics类中的条件判断代码会变得越来越冗长和复杂,维护成本急剧增加 。这时候,工厂方法模式就可以很好地解决这些问题,它将对象的创建和使用分离,让代码更加灵活和可维护。
二、什么是工厂方法模式
2.1 定义与核心原理
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个创建对象的接口,但由子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。简单来说,工厂方法模式将对象的创建和使用分离,把对象创建的具体过程封装在工厂类的子类中,这样可以降低代码之间的耦合度 ,提高代码的可维护性和可扩展性。在前面的物流管理系统例子中,我们不再在业务代码中直接使用new关键字创建运输对象,而是通过工厂类的方法来创建,具体创建哪种运输对象由工厂类的子类决定。 这种方式使得当我们需要添加新的运输方式时,只需要增加一个新的具体工厂类和具体产品类,而不需要修改现有的业务逻辑代码,这正是工厂方法模式的核心优势所在。
2.2 模式结构详解
工厂方法模式主要包含以下四个角色:
-
抽象产品(Product):定义了产品的接口,是工厂方法所创建对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在物流系统中,Transport接口就是抽象产品,它定义了deliver方法,所有具体的运输方式(如卡车运输、轮船运输、航空运输等)都需要实现这个接口。
// 抽象产品:运输接口
public interface Transport {
void deliver();
}
-
具体产品(ConcreteProduct):实现了抽象产品接口,提供产品的具体实现。例如Truck类和Ship类就是具体产品,它们分别实现了Transport接口的deliver方法,提供了各自的运输方式实现。
// 具体产品:卡车运输类
class Truck implements Transport {
@Override
public void deliver() {
System.out.println("货物通过卡车运输");
}
}
// 具体产品:轮船运输类
class Ship implements Transport {
@Override
public void deliver() {
System.out.println("货物通过轮船运输");
}
}
-
抽象工厂(Creator):声明了工厂方法,用于返回一个产品对象。可以包含产品创建的默认实现。在物流系统中,Logistics类可以作为抽象工厂,它声明了一个抽象的createTransport方法,用于创建运输对象。
// 抽象工厂:物流类
public abstract class Logistics {
public abstract Transport createTransport();
// 物流系统的核心业务逻辑,依赖于createTransport方法返回的产品对象
public void planDelivery() {
Transport transport = createTransport();
transport.deliver();
}
}
-
具体工厂(ConcreteCreator):实现了工厂方法,返回具体产品的实例。例如RoadLogistics类和SeaLogistics类就是具体工厂,它们分别实现了Logistics类的createTransport方法,返回Truck对象和Ship对象。
// 具体工厂:公路物流类
class RoadLogistics extends Logistics {
@Override
public Transport createTransport() {
return new Truck();
}
}
// 具体工厂:海运物流类
class SeaLogistics extends Logistics {
@Override
public Transport createTransport() {
return new Ship();
}
}
在这个模式中,客户端(如物流管理系统的使用者)只需要与抽象工厂和抽象产品进行交互,而不需要关心具体产品的创建细节和具体工厂的实现。当需要添加新的运输方式时,只需要添加新的具体产品类(如Airplane类表示航空运输)和具体工厂类(如AirLogistics类),并实现相应的接口和方法即可,现有代码的修改量极小,这大大提高了系统的可扩展性和维护性。