一、定义
工厂方法模式(Factory Method Pattern):创新型模式之一,简称工厂模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
二、UML类图
三、角色职责
- 抽象产品(Product):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。
- 具体产品(Concrete Product):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。
- 抽象工厂(Factory):在抽象工厂类中声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。
- 具体工厂(Concrete Factory):它是抽象工厂类的子类,实现了在抽象工厂中声明的工厂方法,并可由客户端调用,返回一个具体产品类的实例。
四、代码实现
前言:在简单工厂模式中,我们每需要增加一个品牌的篮球,就需要修改一次工厂,非常麻烦且复杂,违背了开闭原则。在工厂方法模式中,这个缺陷得到了修复。我们将篮球工厂作为一个抽象工厂,每个品牌的篮球工厂去实现这个抽象工厂,篮球对象的创建由每个工厂去负责,当我们需要新的品牌的篮球时,只需要添加篮球工厂与篮球产品即可,提高了程序的扩展性。
抽象篮球接口(抽象产品类 abstract Product)
public interface BasketBall {
void shot();
}
阿迪达斯篮球(具体产品类 Concrete Product)
public class AdidasBasketBall implements BasketBall {
@Override
public void shot() {
System.out.println("使用阿迪达斯篮球投篮");
}
}
耐克篮球(具体产品类 Concrete Product)
public class NikeBasketBall implements BasketBall {
@Override
public void shot() {
System.out.println("使用耐克篮球投篮");
}
}
斯伯丁篮球(具体产品类 Concrete Product)
public class SpaldingBasketBall implements BasketBall {
@Override
public void shot() {
System.out.println("使用斯伯丁篮球投篮");
}
}
抽象篮球工厂接口(抽象工厂类 Factory)
public interface BasketBallFactory {
public BasketBall make();
}
阿迪达斯篮球工厂(具体工厂类 Concrete Factory)
public class AdidasBasketBallFactory implements BasketBallFactory {
@Override
public BasketBall make() {
return new AdidasBasketBall();
}
}
耐克篮球工厂(具体工厂类 Concrete Factory)
public class NikeBasketBallFactory implements BasketBallFactory {
@Override
public BasketBall make() {
return new NikeBasketBall();
}
}
斯伯丁篮球工厂(具体工厂类 Concrete Factory)
public class SpaldingBasketBallFactory implements BasketBallFactory {
@Override
public BasketBall make() {
return new SpaldingBasketBall();
}
}
测试类
public class FactoryMethodTest {
public static void main(String[] args) {
// 使用阿迪达斯篮球投篮
BasketBallFactory adidasBasketBallFactory = new AdidasBasketBallFactory();
adidasBasketBallFactory.make().shot();
// 使用耐克篮球投篮
BasketBallFactory nikeBasketBallFactory = new NikeBasketBallFactory();
nikeBasketBallFactory.make().shot();
// 使用斯伯丁篮球投篮
BasketBallFactory spaldingBasketBallFactory = new SpaldingBasketBallFactory();
spaldingBasketBallFactory.make().shot();
}
}
五、源码分析
工厂方法模式应用的地方非常广泛,在Spring中就有很多使用了工厂方法模式的地方。
其中AbstractApplicationContext就是ApplicationContext接口的实现抽象类。
AbstractApplicationContext的子类AbstractRefreshableApplicationContext就实现了这个抽象方法,使用了这个工厂方法去创建了实例。
这样类的设计与真正的实现之间其实是松耦合的,也正好符合了设计的开闭原则。
六、优缺点分析
优点:
- 用户只需要关心所需产品对应的工厂,无需关心创建细节。
- 加入新产品 时, 只需要添加一个具体工厂和具体产品 , 提高可扩展性,符合开闭原则。
- 工厂方法模式中 , 使用工厂类创建产品对象 , 同时隐藏了具体的产品类被实例化的细节 。
缺点:
- 在添加新产品时 , 除了编写新的产品类 , 还要编写该产品类对应的工厂类,增加系统复杂度。
七、适用场景
在日志记录与访问的数据库未知时,会有较多的适用。客户端对需要对象的类未知时,抽象工厂类通过其子类来指定创建哪个对象。通过多态性,在程序运行时子类覆盖父类对象,从而使得系统更容易扩展。
八、总结
工厂方法模式中核心的工厂类不再负责对相应子类的创建,而是声明一个子工厂类必须实现的接口,具体的实例化工作由子工厂类去做,提高了程序的扩展性,符合开闭原则。但在新增一个新产品时,就要新增一个具体工厂和一个具体产品,会增加代码量。
工厂方法模式克服了简单工厂违背开放闭原则的缺点,又保持了封装对象创建过程的优点。