前言
在上文提到的简单工厂模式中,发现简单工厂模式存在一系列问题:
工厂类集中了所有产品的创建逻辑,一旦这个工厂类不能正常工作,整个系统都会受到巨大的影响。
违背开闭原则。一旦添加新产品时,不是通过新增类解决,而是通过修改原先的工厂类逻辑来解决。这样会造成工厂类静态工厂方法逻辑过于复杂。
简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。
为了解决上述的问题,我们又使用了一种新的设计模式:工厂方法模式
工厂方法模式的定义
工厂方法模式,又称工厂模式、多态工厂模式。通过定义父类工厂负责定义创建对象的公共接口,而子类则负责生成具体的对象。
工厂方法模式的作用
将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成。(简单工厂模式中,是将具体产品的创建延迟到具体产品子类中去创建)既由具体工厂来决定应该实例话哪一种产品。
工厂模式方法将具体产品的创建过程延迟到工厂类的子类中。此时工厂类不再负责所有产品的创建逻辑。而是仅仅给出具体工厂必须实现的接口。这样在新增产品的时候。就不需要更改抽象工厂类。而是只需要新增新的工厂实现子类就可以了。符合了开闭原则。克服了简单工厂模式的缺点
工厂模式的UML
工厂模式使用步骤
创建抽象工厂类,定义具体工厂的公共接口
创建抽象产品类,定义具体产品的公共接口
创建具体产品类,定义生产的具体产品
创建具体接口类,重写抽象工厂类的公共接口来创建不同的具体产品类
外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
工厂方法模式优点
更符合开闭原则。新增一种产品时,只需要添加相应的具体产品类和相应的工厂子类即可。而简单工厂模式需要修改工厂类的判断逻辑
符合单一职责原则,每个具体工厂类只负责创建对应的产品。而简单工厂模式中的工厂类存在复杂的switch-case 或者 if-else逻辑判断
不使用静态工厂方法,可以形成基于继承的等级结构。而简单工厂模式中的工厂类使用的是静态工厂方法。
工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。
工厂方法模式的应用常见场景
在一个类不知道他所需要的对象的类时。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可。
当一个类希望通过其子类来制定创建对象时。在工厂方法模式中,抽象工厂类只需要提供一个创建产品的接口,返回的抽象产品父类。而由其子类来确定要创建的具体产品对象。多态,易拓展。
将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类。需要时再动态指定,可将具体工厂类的类名存在在配置文件或者数据库中。通过反射中的newInstance创建对象。
工厂方法模式的缺点
添加一个新产品就得添加一个具体的工厂类。系统类的个数将成对增加。一定程度上增加了系统的复杂度和开销
一个具体工厂只能创建一种具体产品
代码实例
package com.dding.pmsmigrateServer.test; //客户端 public class Test { public static void main(String[] args) { } } //定义抽象工厂 interface AbstractFactory{ AbstractProduct getProduct(); } //定义抽象产品类 interface AbstractProduct{ void show(); } //定义具体产品子类apple class Apple implements AbstractProduct{ public void show(){ System.out.println("apple"); } } //定义具体产品子类monce class Mouce implements AbstractProduct{ public void show(){ System.out.println("monce"); } } //定义具体的产品子类cat class Cat implements AbstractProduct{ public void show(){ System.out.println("cat"); } } //定义生产apple的工厂子类 class AppleFactory implements AbstractFactory{ public AbstractProduct getProduct(){ return new Apple(); } } //定义生产mouce的工厂子类 class MonceFactory implements AbstractFactory{ public AbstractProduct getProduct(){ return new Mouce(); } }