工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现开闭原则,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。
工厂方法模式对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不再负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。
工厂方法模式(Factory Method pattern)是最典型的模板方法模式(Template Method pattern)应用。
它的核心结构有四个角色,分别是抽象工厂;具体工厂;抽象产品;具体产品。
上一篇博客简单工厂模式案例中不符合开闭原则,所以又衍生出一种更加好的生产方式,这就是工厂方法模式。把生产勇士的工厂类抽象成接口或抽象类,让具体的工厂类实现接口或继承抽象类,需要哪个类型的勇士就实例化那种工厂,生产出具体的勇士来。简单工厂中不存在的魔法师这里就将它创建出来。
采用抽象类代替接口,抽象类可以更好地实现模板功能。
/**
* 抽象的勇士
*/
public abstract class AbstractFighter {
//勇士编号
private int id;
public AbstractFighter(int id) {
this.id = id;
}
public void say() {
System.out.println("我是" + this.getFighterType().getTypeName() + ", 编号:" + this.id);
}
abstract FighterType getFighterType();
}
约束勇士种类,传参可视化。
/**
* 勇士类型枚举
*/
public enum FighterType {
Gunner("神枪手"),
Swordman("鬼剑士"),
Mage("魔法师");
private String typeName;
private FighterType(String typeName) {
this.typeName = typeName;
}
public String getTypeName() {
return this.typeName;
}
}
使用原子操作类AtomicInteger,利用唯一编号动态管理同类对象。
/**
* 神枪手
*/
public class Gunner extends AbstractFighter {
private static AtomicInteger fighterID = new AtomicInteger(0);
public Gunner() {
super(fighterID.addAndGet(1));
}
@Override
FighterType getFighterType() {
return FighterType.Gunner;
}
}
/**
* 鬼剑士
*/
public class Swordman extends AbstractFighter {
private static AtomicInteger fighterID = new AtomicInteger(0);
public Swordman() {
super(fighterID.addAndGet(1));
}
@Override
FighterType getFighterType() {
return FighterType.Swordman;
}
}
以上代码均与简单工厂模式中一样,变化的是工厂,代码如下:
/**
* 抽象的勇士工厂
*/
public abstract class AbstractFighterFactory {
/**
* 抽象方法-创建勇士
* @return
*/
public abstract AbstractFighter createFighter();
}
/**
* 神枪手工厂
*/
public class GunnerFactory extends AbstractFighterFactory {
@Override
public AbstractFighter createFighter() {
return new Gunner();
}
}
/**
* 鬼剑士工厂
*/
public class SwordmanFactory extends AbstractFighterFactory {
@Override
public AbstractFighter createFighter() {
return new Swordman();
}
}
public class FactoryMethodTest {
public static void main(String[] args) {
//创建神枪手工厂
AbstractFighterFactory gunnerFactory = new GunnerFactory();
//创建神枪手
AbstractFighter fighter1_1 = gunnerFactory.createFighter();
fighter1_1.say();
AbstractFighter fighter1_2 = gunnerFactory.createFighter();
fighter1_2.say();
//创建鬼剑士工厂
AbstractFighterFactory swordmanFactory = new SwordmanFactory();
//创建鬼剑士
AbstractFighter fighter2_1 = swordmanFactory.createFighter();
fighter2_1.say();
AbstractFighter fighter2_2 = swordmanFactory.createFighter();
fighter2_2.say();
}
}
输出结果如下:
我是神枪手, 编号:1
我是神枪手, 编号:2
我是鬼剑士, 编号:1
我是鬼剑士, 编号:2
如果我需要再创建一个魔法师,我只需写一个具体的魔法师类(继承抽象的勇士类)和一个魔法师工厂(继承抽象的勇士工厂即可),不需要修改源代码。
/**
* 魔法师
*/
public class Mage extends AbstractFighter {
private static AtomicInteger fighterID = new AtomicInteger(0);
public Mage() {
super(fighterID.addAndGet(1));
}
@Override
FighterType getFighterType() {
return FighterType.Mage;
}
}
/**
* 魔法师工厂
*/
public class MageFactory extends AbstractFighterFactory {
@Override
public AbstractFighter createFighter() {
return new Mage();
}
}
public class FactoryMethodTest {
public static void main(String[] args) {
//创建魔法师工厂
AbstractFighterFactory mageFactory = new MageFactory();
//创建魔法师
AbstractFighter fighter3_1 = mageFactory.createFighter();
fighter3_1.say();
AbstractFighter fighter3_2 = mageFactory.createFighter();
fighter3_2.say();
}
}
输出结果如下:
我是魔法师, 编号:1
我是魔法师, 编号:2
工厂方法模式克服了简单工厂会违背开闭原则的缺点,又保持了封装对象创建过程的优点。
符合单一职责原则,每个具体工厂类只负责创建对应的产品。
每增加一个产品类,就需要增加一个对应的产品工厂类,增加了额外的开发量。