工厂方法模式的扩展

时间:2022-06-08 07:14:43

工厂方法模式有很多扩展,而且与其他模式结合使用威力更大,下面将介绍几种扩展。

1. 缩小为简单工厂模式

我们这样考虑一个问题:一个模块仅需要一个工厂类,没有必要把它产生出来,使用静态的方法就可以了,根据这一要求,我们把上例中的AbstarctHumanFactory修改一下,类图如

工厂方法模式的扩展

我们在类图中去掉了AbstractHumanFactory抽象类,同时把createHuman方法设置为静态
类型,简化了类的创建过程,变更的源码仅仅是HumanFactory和NvWa类,HumanFactory如代
码清单8-13所示。
代码清单8-13 简单工厂模式中的工厂类

public class HumanFactory {
public static <T extends Human> T createHuman(Class<T> c){
//定义一个生产出的人种
Human human=null;
try {
//产生一个人种
human = (Human)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
System.out.println("人种生成错误!");
}
return (T)human;
}
}

HumanFactory类仅有两个地方发生变化:去掉继承抽象类,并在createHuman前增加static
关键字;工厂类发生变化,也同时引起了调用者NvWa的变化,如代码清单8-14示。

代码清单8-14 简单工厂模式中的场景类

public class NvWa {
public static void main(String[] args) {
//女娲第一次造人,火候不足,于是白色人种产生了
System.out.println("--造出的第一批人是白色人种--");
Human whiteHuman = HumanFactory.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
//女娲第二次造人,火候过足,于是黑色人种产生了
System.out.println("\n--造出的第二批人是黑色人种--");
Human blackHuman = HumanFactory.createHuman(BlackHuman.class);
blackHuman.getColor();
blackHuman.talk();
//第三次造人,火候刚刚好,于是黄色人种产生了
System.out.println("\n--造出的第三批人是黄色人种--");
Human yellowHuman = HumanFactory.createHuman(YellowHuman.class);
yellowHuman.getColor();
yellowHuman.talk();
}
}

运行结果没有发生变化,但是我们的类图变简单了,而且调用者也比较简单,该模式是工厂方法模式的弱化,因为简单,所以称为简单工厂模式(Simple Factory Pattern),也叫做静态工厂模式。在实际项目中,采用该方法的案例还是比较多的,其缺点是工厂类的扩展比较困难,不符合开闭原则,但它仍然是一个非常实用的设计模式。

2. 升级为多个工厂类

当我们在做一个比较复杂的项目时,经常会遇到初始化一个对象很耗费精力的情况,所有的产品类都放到一个工厂方法中进行初始化会使代码结构不清晰。例如,一个产品类有5个具体实现,每个实现类的初始化(不仅仅是new,初始化包括new一个对象,并对对象设置一定的初始值)方法都不相同,如果写在一个工厂方法中,势必会导致该方法巨大无比,那该怎么办?

考虑到需要结构清晰,我们就为每个产品定义一个创造者,然后由调用者自己去选择与哪个工厂方法关联。我们还是以女娲造人为例,每个人种都有一个固定的八卦炉,分别造出黑色人种、白色人种、黄色人种,修改后的类图如图所示。
工厂方法模式的扩展

每个人种(具体的产品类)都对应了一个创建者,每个创建者都独立负责创建对应的产品对象,非常符合单一职责原则,按照这种模式我们来看看代码变化。
多工厂模式的抽象工厂类如代码清单8-15所示。
代码清单8-15 多工厂模式的抽象工厂类

public abstract class AbstractHumanFactory {
public abstract Human createHuman();
}

 抽象方法中已经不再需要传递相关参数了,因为每一个具体的工厂都已经非常明
确自己的职责:创建自己负责的产品类对象。
黑色人种的创建工厂如代码清单8-16所示。
代码清单8-16 黑色人种的创建工厂实现

public class BlackHumanFactory extends AbstractHumanFactory{
public Human createHuman() {
return new BlackHuman();
}
}

黄色人种的创建工厂如代码清单8-17所示。
代码清单8-17 黄色人种的创建类

public class YellowHumanFactory extends AbstractHumanFactory {
public Human createHuman() {
return new YellowHuman();
}
}

白色人种的创建工厂如代码清单8-18所示。
代码清单8-18 白色人种的创建类

public class whiteHumanFactory extends AbstractHumanFactory {
public Human createHuman() {
return new WhiteHuman();
}
}

三个具体的创建工厂都非常简单,但是,如果一个系统比较复杂时工厂类也会相应地变复杂。场景类NvWa修改后的代码如代码清单8-19所示。

public class NvWa {
public static void main(String[] args) {
//女娲第一次造人,火候不足,于是白色人种产生了
System.out.println("--造出的第一批人是白色人种--");
Human whiteHuman = (new WhiteHumanFactory()).createHuman();
whiteHuman.getColor();
whiteHuman.talk();
//女娲第二次造人,火候过足,于是黑色人种产生了
System.out.println("\n--造出的第二批人是黑色人种--");
Human blackHuman = (new BlackHumanFactory()).createHuman();
blackHuman.getColor();
blackHuman.talk();
//第三次造人,火候刚刚好,于是黄色人种产生了
System.out.println("\n--造出的第三批人是黄色人种--");
Human yellowHuman = (new YellowHumanFactory()).createHuman();
yellowHuman.getColor();
yellowHuman.talk();
}
}

运行结果还是相同。我们回顾一下,每一个产品类都对应了一个创建类,好处就是创建类的职责清晰,而且结构简单,但是给可扩展性和可维护性带来了一定的影响。为什么这么说呢?如果要扩展一个产品类,就需要建立一个相应的工厂类,这样就增加了扩展的难度。

因为工厂类和产品类的数量相同,维护时需要考虑两个对象之间的关系。
当然,在复杂的应用中一般采用多工厂的方法,然后再增加一个协调类,避免调用者与各个子工厂交流,协调类的作用是封装子工厂类,对高层模块提供统一的访问接口。

本文摘引自《设计模式之禅(第2版)》
本文源码:https://github.com/527515025/Design_pattern