前言
上一篇,我们介绍了简单工厂模式,它适用于产品数量较少且固定的情况,如果产品数量多或不固定,那么该模式会存在扩展性的问题。
所以,接下来我们介绍另一个具有扩展性且符合开闭原则的工厂模式–工厂方法模式。
开源车型创建框架
假设,我们把下面的代码开源到github上,作为智能配送程序的实现框架。
//请叫我“车型创建框架”,我可以避免你重复造轮子
public class CarFactory {
//多态地创建产品
public static Car create(Package package){
Car car ;
if(package.getWeight()<=10){
car = new Bike();
}else if (package.getWeight()<20){
car = new Tricycle();
}else{
System.out.println("敬请期待!");
}
//所有的车子必须初始化,才能使用
car.init();
return car;
}
}
开源后不久,我们收到了两条反馈信息:
1、我们除了有Bike和Tricycle外,还有载重30GK的卡车,但你的框架无法扩展我们自己的产品;
2、我们需要自行控制产品的创建条件(我们车子载重不允许超过标准的80%),但框架中把创建条件写死了。
抽象创建行为
第一个问题:无法扩展自定义的产品,我们只需要去掉static关键字,让CarFactory可继承,同时对外提供一个扩展点doCreate。如下:
//通过继承CarFactory实现自定义产品的扩展
public abstract class CarFactory {
//去掉static关键字,让改方法可以被继承
public Car create(Package package){
Car car ;
if(package.getWeight()<=10){
car = new Bike();
}else if (package.getWeight()<20){
car = new Tricycle();
}else{
//如果是框架之外的产品,调用子类的方法
car=doCreate(package);
}
//所有的车子必须初始化,才能使用
car.init();
return car;
}
//对外提供扩展点,用于创建框架之外的产品
public abstract Car doCreate(Package package);
}
工厂方法模式
如果只是解决第一个问题,那么这样重构就可以了。但要解决第二个问题:“创建产品的条件写死了”,那我们需要去掉创建产品的条件和行为,让使用者能根据自身的实际情况创建产品。
//我绝对符合开闭原则:扩展开发,修改关闭
public abstract class CarFactory {
//声明为final,关闭子类对该方法的修改
public final Car create(){
//去掉“个性化”的部分后,剩下的代码都是稳定不变的
Car car =doCreate();
car.init();
return car;
}
//我是对创建行为的抽象,用于创建框架之外的产品
public abstract Car doCreate();
}
去掉创建产品的条件和行为后,如果直接把Bike和Tricycle暴露出去了,这就违背了我们使用工厂创建产品的初衷:隔离产品变化对客户类的影响。
既然CarFactory能支持自定义产品的扩展,当然也能支持框架提供的产品的扩展。所以,我们可以为每一个产品提供一个工厂,来隔离变化对客户类的影响。
//我的目的是隔离变化对客户类的影响
public class BikeFactory extends CarFactory{
public Car doCreate(){
return new Bike();
}
}
//我承诺自己的类名、构造函数不发生变化
public class TricycleFactory extends CarFactory{
public Car doCreate(){
return new Tricycle();
}
}
扩展自定义产品
现在,我们模拟一下框架使用者如何扩展自定义产品以及控制产品创建逻辑。
//自定义产品
class Truck implements Car{}
//通过继承抽象工厂扩展自定义产品
class TruckFactory extends CarFactory{}
//机器人
public class Robot {
public static void deliver(Package package){
CarFactory carFactory ;
//自行控制创建产品的条件
if(package.getWeight()<=(10*0.8)){
//创建框架提供的Bike工厂
carFactory = new BikeFactory();
}else if (package.getWeight()<(10*0.8)){
//创建框架提供的Tricycle工厂
carFactory = new TricycleFactory();
}else if(package.getWeight()<(40*0.8)){
//创建自定义的工厂
carFactory = new TruckFactory();
}else{
System.out.println("敬请期待!");
}
//使用具体工厂创建具体产品
Car car = carFactory.create();
//装货
car.load(package);
//开车
car.start();
//停车
car.stop();
//卸货
car.unload();
}
}
可以看出,客户类Robot虽然不依赖具体的产品,但还是依赖了具体的工厂BikeFactory和TruckFactory。
这样,是不是又回到了起点(依赖具体对象)了呢?答案是肯定的,但具体工厂会比具体产品更具稳定,所以哪怕是依赖具体产品,只要是稳定不变的那么也是可行的。