前言
前一篇介绍了《设计模式—简单工厂模式详解》,可以知道简单工厂模式有一些弊端:
- 工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;
- 违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂;
- 简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。
为了解决上述的问题,我们又使用了一种新的设计模式:工厂方法模式。
概述
定义
工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
主要作用
将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。
解决的问题
工厂一旦需要生产新产品就需要修改工厂类的方法逻辑,违背了“开放 - 关闭原则。
之所以可以解决简单工厂的问题,是因为工厂方法模式把具体产品的创建推迟到工厂类的子类(具体工厂)中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式在添加新产品的时候就不修改工厂类逻辑而是添加新的工厂子类,符合开放封闭原则,克服了简单工厂模式中缺点。
模式详细设计思路
如上图UML图所示,工厂方法模式主要包含如下角色:
- 抽象工厂(Factory)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
- 具体工厂(Concrete Factory)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:FactoryA与FactoryB。
- 抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
- 具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
使用步骤
- 创建抽象工厂类,定义具体工厂的公共接口;
- 创建抽象产品类 ,定义具体产品的公共接口;
- 创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
- 创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
- 外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例。
案例(demo)
案例介绍
背景:王老板有一间塑料加工厂(仅生产A类产品);随着客户需求的变化,客户需要生产B类产品;以后可能还会有更多的产品线出现。
痛点:改变原有塑料加工厂的配置和变化非常困难,假设下一次客户需要再发生变化,再次改变将增大非常大的成本;
解决方案:小成决定置办塑料分厂B来生产B类产品,即选择工厂方法模式。
案例实现
创建抽象产品类,如下所示:
package com.linezonedata.dp.factoryMethod;
/**
* @Description: 抽象产品类
* @Author: garrettwang
* @Date: 2019/12/4 21:16
* @Modified By:
*/
public abstract class Product {
/**
* 产品方法
*/
public abstract void show();
}
创建产品具体的类,如下图所示:
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/4 21:17
* @Modified By:
*/
public class ProductA extends Product {
@Override
public void show() {
System.out.println("生产出了产品A");
}
}
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/4 21:18
* @Modified By:
*/
public class ProductB extends Product {
@Override
public void show() {
System.out.println("生产出了产品B");
}
}
创建抽象工厂类,如下所示:
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/5 18:42
* @Modified By:
*/
public abstract class Factory {
public abstract Product createProduct();
}
创建具体工厂类,两个具体工厂类,如下图所示:
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/5 18:43
* @Modified By:
*/
public class FactoryA extends Factory {
@Override
public Product createProduct() {
return new ProductA();
}
}
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/5 18:43
* @Modified By:
*/
public class FactoryB extends Factory {
@Override
public Product createProduct() {
return new ProductB();
}
}
测试代码类,如下所示:
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/4 21:23
* @Modified By:
*/
public class Test {
public static void main(String[] args){
new FactoryA().createProduct().show();
new FactoryB().createProduct().show();
}
}
测试结果如下:
生产出了产品A
生产出了产品B