WHAT
定义
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
(定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方式使一个类的实例化延迟到其子类。)
通用类图
Product:抽象的产品类
定义了产品的共性,实现对事物最抽象的定义
Creator:抽象创建类
抽象工厂
ConcreteCreator:具体的实现工厂
定义具体如何产生具体的产品
WHY
优点
- 良好的封装性,代码结构清晰
- 一个对象创建时有条件约束的
- 只要知道产品的类名就可以,不需要知道具体如何创建对象,降低模块之间的耦合
- 扩展性非常优秀
- 增加产品类的情况下,需要适当地修改决堤的工厂类或扩展一个工厂类,就可以完成修改。
- 屏蔽产品类
- 产品类的实现如何变化,调用者不需要关心,只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不会发生变化
- 数据库开发中,如果说那个JDBC连接数据库,从MySQL切换到Oracle,需要改动的地方就是切换一下驱动名称
- 典型的解耦框架
- 高层模块只需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则
- 只依赖产品类的抽象,符合依赖倒置原则
- 使用产品子类替换产品父类,符合里氏替换原则
缺点
- 增加了代码的复杂度
HOW
使用场景
- 工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用
- 但需要慎重考虑是否增加一个工厂类进行管理,会增加代码的复杂度
- 需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式
- 数据库驱动 - MySQL、Oracle等
- 设计一个连接邮件服务器的框架
- 有三种网络协议可供选择:POP3、IMAP、HTTP,作为具体的产品类
- IConnectMail,作为抽象产品类,定义对邮件的操作方法
- 定义抽象工厂
- 实现具体工厂
- 如果需要增加WebService接口,只需要增加一个产品类就好了
- 工厂方法模式可以用在异构项目中
- 通过WebService与一个非Java的项目交互
扩展
-
简单工厂模式 (Simple Factory Pattern)
- 也称作:静态工厂模式
- 优点
- 简化继承抽象类
- 将创建方法设置为静态类型,简化类的创建过程
- 缺点
- 扩展比较困难
- 不符合开闭原则
-
多个工厂类
- 场景
- 一个产品类有5个具体实现,每个实现类的初始化方法都不相同,如果写在一个工厂方法中,势必会导致该方法巨大无比
- 操作
- 为每个产品定义一个创造者,然后由调用者自己去选择与哪个工厂方法关联
- 实现
interface IProduct
- 定义产品类的公用方法ProductA
- 定义具体的产品类AbstractProductFactory
- 定义产品的抽象工厂ProductAFactory
- 具体的产品A的工厂
- TIPS
- 抽象方法中不再需要传递相关参数,因为每个具体的工厂都已经非常明确自己的职责:创建自己负责的产品类对象
- 复杂应用中一般采用多工厂的方法,再增加一个协调类,避免调用者与各个子工厂交流,就是封装了子工厂类,对高层模块提供统一的访问接口。
- 优势
- 创建类的职责清晰,结构简单
- 劣势
- 降低了可扩展性和可维护性
- 要扩展一个产品类,需要建立一个相应的工厂类,增加了扩展的难度
- 降低了可扩展性和可维护性
- 场景
-
替代单例模式
-
单例模式的核心要求是内存中只有一个对象,通过工厂方法模式也可以只在内存中生产一个对象
-
类图
-
单例类不能通过正常渠道建立一个对昂,那个单例工厂通过如何创建一个单例对象呢?
-
通过反射方式
public class SingletonFactory{ private static Singleton singleton; static { try { Class cl = Class.forName(Singleton.class.getName()); // 获得无参构造 Constructor constructor = cl.getDeclaredConstructor(); //设置无参构造是可访问的 constructor.setAccessible(true); //产生一个实例对象 singleton = (Singleton)constructor.newInstance(); }catch(Exception e){ // 异常处理 } } public static Singleton getSingleton(){ return singleton; } }
-
-
-
延迟初始化 - Lazy initialization
-
一个对象被消费完毕后,并不立即释放,工厂类保持其初始状态,等待再次被使用
-
类图
- 通过定义一个Map容器,容纳所有生成的对象;如果有则取出返回,如果没有则创建后放入Map中再放回
-
可以继续扩展
- 限制某一个产品类的最大实例化数量
-
使用场景
- 设置产品类的最大实例化数量
- 对象初始化比较复杂的情况下,降低对象产生和销毁带来的复杂性
-
最佳实践
熟练掌握工厂方法模式,多思考工厂方法如何应用,而且工厂方法模式还可以与其他模式混合使用(例如模板方法模式、单例模式、原型模式等)。
《设计模式之禅》第八章 工厂方法模式