在设计模式—简单工厂模式中提到了该模式的几点弊端:
- 工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;
- 违背“开闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂;
- 简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构
为了解决这些弊端,出现了工厂方法模式。
工厂方法模式(Factory Method Pattern),其定义如下: :::info Define an interface for creating an object,but let subclasses decide whichclass to instantiate.Factory Method lets a class defer instantiation tosubclasses.
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。 :::
- 存在工厂的抽象基类,规定创建产品的原则与规则;
- 每个工厂实现类创建不同的产品,符合开闭原则,也可以合适地利用继承等语言特性。
也就是说,工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
其组成模型如下:
| 组成 | 关系 | 作用 |
|---|---|---|
| 抽象产品(Product) | 具体产品的父类 | 提供描述产品的公共接口 |
| 具体产品(Concrete Product) | 具体产品类,工厂生产的目标类 | 抽象产品具体化 |
| 抽象工厂(Factory) | 具体工厂的父类 | 描述具体工厂的公共接口 |
| 具体工厂(Concrete Factory) | 抽象工厂的子类;被外界调用 | 描述具体工厂;实现FactoryMethod工厂方法创建产品的实例 |
工厂方法模式的优点
- 封装性良好,代码结构清晰,符合单一职责原则;
- 良好的扩展性,符合开闭原则
工厂方法的缺点
- 增加新产品,必随着增加新工厂。类个数成对增加,增加系统复杂性;
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度;
- 一个具体工厂只能创建一种具体产品
工厂方法模式最佳实践
- 当一个类不知道它所需要的对象的类时;在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可;
- 当一个类希望通过其子类来指定创建对象时;在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展;
- 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中;
工厂方法模式实现步骤
- 创建抽象产品,定义产品的公共能力;
- 创建具体产品类,实现自己的独有能力;
- 创建抽象工厂,定义生产的公共能力;
- 创建具体工厂类,实现自己的生成能力,具体到能生产哪种产品;
- 外界调用具体工厂生成具体产品。
工厂方法模式使用示例
使用工厂方法模式生产不同的Pencil。
public class FactoryMethod {/*** 抽象产品类,并定义具体产品的基本功能*/public interface IPencil {void write();}/*** 具体产品类:钢笔*/public static class Fountain implements IPencil {@Overridepublic void write() {System.out.println("使用钢笔写字");}}/*** 具体产品类:铅笔*/public static class Pencil implements IPencil {@Overridepublic void write() {System.out.println("使用铅笔写字");}}/*** 工厂抽象,提供生产产品的方法*/public interface IFactory {IPencil createPencil();}/*** 钢笔类工厂*/public static class FountainFactory implements IFactory {@Overridepublic IPencil createPencil() {return new Fountain();}}/*** 铅笔类工厂*/public static class PencilFactory implements IFactory {@Overridepublic IPencil createPencil() {return new Pencil();}}public static void main(String[] args) {// 生产铅笔new PencilFactory().createPencil().write();// 生产钢笔new FountainFactory().createPencil().write();}}
输出结果:
**
:::success
使用铅笔写字
使用钢笔写字
:::
