Java设计模式之创建型模式 | 工厂模式

53 阅读6分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 11 天,点击查看活动详情

觉得对你有益的小伙伴记得点个赞+关注

后续完整内容持续更新中

希望一起交流的欢迎发邮件至javalyhn@163.com

1. 工厂模式定义

提供了一种创建对象的最佳方式。我们不必关心对象的创建细节,只需要根据不同情况获取不同产品即可。

image.png

工厂模式分为三种:

  1. 简单工厂(Simple Factory)静态工厂
  2. 工厂方法(Factorty Method)多态工厂
  3. 抽象工厂(Abstract Factory)

2. 工厂模式使用场景

  • NumberFormat、SimpleDateFormat
  • LoggerFactory:
  • SqlSessionFactory:MyBatis
  • BeanFactory:Spring的BeanFactory(就是为了造出bean)

3. 简单工厂的实现

我们假设有下面一个造车的场景

image.png

有三个角色:

  • Factory:工厂角色, WuLinFactory
  • Product:抽象产品角色,Car
  • ConcreteProduct:具体产品角色, VanCar、MiniCar

Car

/**
 * 工厂的产品
 */
public abstract class AbstractCar {

    String engine;
    public abstract void run();
}

VanCar

/**
 * 具体产品
 */
public class VanCar extends AbstractCar{
    public VanCar(){
        this.engine = "单杠柴油机";
    }

    @Override
    public void run() {
        System.out.println(engine+"--》嗒嗒嗒....");
    }
}

MiniCar

public class MiniCar extends AbstractCar{

    public MiniCar(){
        this.engine = "四缸水平对置发动机";
    }

    @Override
    public void run() {
        System.out.println(engine+"--> 嘟嘟嘟...");
    }
}
WuLinSimpleFactory

/**
 * 简单工厂
 * 1、产品数量极少
 */
public class WuLinSimpleFactory {

    /**
     *
     * @param type  Class: 好像具有扩展性,但是没有解决实际问题
     * @return
     */
    public AbstractCar newCar(String type){

        //核心方法:一切从简
        if("van".equals(type)){
            // 钣金、喷漆、放发动机、申请环保

            return new VanCar();
        }else if("mini".equals(type)){
            return new MiniCar();
        }

        //.....

        //更多的产品,违反开闭原则。应该直接扩展出一个类来造
        return null;
    }
}

MainTest

public class MainTest {

    public static void main(String[] args) {

        WuLinSimpleFactory factory = new WuLinSimpleFactory();

        AbstractCar van = factory.newCar("van");
        AbstractCar mini = factory.newCar("mini");
        AbstractCar zz = factory.newCar("zz");
        van.run();
        mini.run();

    }
}

image.png

这个简单工厂方法相信大家一看就知道弊端:if...else... 不符合开闭原则,而且仅适用于类数量少的情况。

4. 工厂方法的实现

这次同样使用造车的场景,但是有区别

image.png

这次有四个角色

  • Product:抽象产品
  • ConcreteProduct:具体产品
  • Factory:抽象工厂
  • ConcreteFactory:具体工厂

AbstractCar

/**
 * 工厂的产品
 *
 * 怎么把一个功能提升一个层次:定义抽象(抽象类,接口)
 * 抽象类,接口  就会有多实现,多实现自然就有多功能
 */
public abstract class AbstractCar {

    String engine;
    public abstract void run();
}

VanCar

/**
 * 具体产品
 */
public class VanCar extends AbstractCar{
    public VanCar(){
        this.engine = "单杠柴油机";
    }

    @Override
    public void run() {
        System.out.println(engine+"--》嗒嗒嗒....");
    }
}

RacingCar

public class RacingCar extends AbstractCar{

    public RacingCar(){
        this.engine = "v8发动机";
    }
    @Override
    public void run() {
        System.out.println(engine+"=--嗖.....");
    }
}

MiniCar

public class MiniCar extends AbstractCar{

    public MiniCar(){
        this.engine = "四缸水平对置发动机";
    }

    @Override
    public void run() {
        System.out.println(engine+"--> 嘟嘟嘟...");
    }
}

AbstractCarFactory

/**
 * 抽象工厂的层级
 */
public abstract class AbstractCarFactory {

    public abstract AbstractCar newCar();
    //我能造口罩.....
}

WulinMinCarFactory

/**
 * minicar分厂
 */
public class WulinMinCarFactory extends AbstractCarFactory{
    @Override
    public AbstractCar newCar() {
        return new MiniCar();
    }
}

WulinRacingCarFactory

/**
 * RacingCar分厂
 */
public class WulinRacingCarFactory extends AbstractCarFactory{
    @Override
    public AbstractCar newCar() {
        return new RacingCar();
    }
}

WulinVanCarFactory

public class WulinVanCarFactory extends AbstractCarFactory {
    @Override
    public AbstractCar newCar() {
        return new VanCar();
    }
}

MainTest

public class MainTest {

    public static void main(String[] args) {
        AbstractCarFactory carFactory = new WulinRacingCarFactory();
        AbstractCar abstractCar = carFactory.newCar();
        abstractCar.run();


        carFactory = new WulinVanCarFactory();
        AbstractCar abstractCar1 = carFactory.newCar();

        abstractCar1.run();
    }
}

image.png

可见,我们省去了ifelse判断,使用了多态方式来建造对象,因此也有十分多的类。

缺点是:缺点:系统复杂度增加,产品单一

5. 抽象工厂的实现

抽象工厂模式: 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。

image.png

每一个工厂都有它的产品族,每个产品族都有对应的产品,实现了想要什么就造什么的情景。

image.png

WulinFactory

/**
 * 总厂规范:
 * Wulin集团
 *
 * 使用接口;
 */
public abstract class WulinFactory {

    List<String> rules;

    abstract AbstractCar newCar();
    abstract AbstractMask newMask();
}

WulinCarFactory

/**
 * wulin 汽车集团
 */
public  abstract  class WulinCarFactory extends WulinFactory{
    @Override
    abstract  AbstractCar newCar();

    @Override
    AbstractMask newMask() {
        return null;
    }
}

WulinVanCarFactory

/**
 * 分厂:VanCar
 */
public class WulinVanCarFactory extends WulinCarFactory{
    @Override
    AbstractCar newCar() {
        return new VanCar();
    }

}

WulinRacingCarFactory

/**
 * 具体工厂。只造车
 */
public class WulinRacingCarFactory extends WulinCarFactory {
    @Override
    AbstractCar newCar() {
        return new RacingCar();
    }
}

AbstractCar

/**
 * 工厂的产品
 *
 * 怎么把一个功能提升一个层次:定义抽象(抽象类,接口)
 * 抽象类,接口  就会有多实现,多实现自然就有多功能
 */
public abstract class AbstractCar {

    String engine;
    public abstract void run();
}

VanCar

/**
 * 具体产品
 */
public class VanCar extends AbstractCar {
    public VanCar(){
        this.engine = "单杠柴油机";
    }

    @Override
    public void run() {
        System.out.println(engine+"--》嗒嗒嗒....");
    }
}

RacingCar

public class RacingCar extends AbstractCar {

    public RacingCar(){
        this.engine = "v8发动机";
    }
    @Override
    public void run() {
        System.out.println(engine+"=--嗖.....");
    }
}

以上是汽车工厂,下面是口罩工厂

WulinHangZhouMaskFactory

/**
 * 只造口罩
 */
public class WulinHangZhouMaskFactory extends WulinMaskFactory {

    @Override
    AbstractMask newMask() {
        return new CommonMask();
    }
}

WulinMaskFactory

/**
 * wulin口罩集团
 */
public abstract class WulinMaskFactory extends WulinFactory{
    @Override
    AbstractCar newCar() {
        return null;
    }


    abstract AbstractMask newMask();
}

WulinHangZhouMaskFactory

/**
 * 只造口罩
 */
public class WulinHangZhouMaskFactory extends WulinMaskFactory {

    @Override
    AbstractMask newMask() {
        return new CommonMask();
    }
}

WulinWuHanMaskFactory

/**
 * 分厂:口罩
 */
public class WulinWuHanMaskFactory  extends WulinMaskFactory{

    @Override
    AbstractMask newMask() {
        return new N95Mask();
    }
}

AbstractMask

/**
 * 抽象产品
 */
public abstract class AbstractMask {

    Integer price;
    public abstract void protectedMe();
}

CommonMask

public class CommonMask  extends AbstractMask{
    public CommonMask(){
        price = 1;
    }
    @Override
    public void protectedMe() {
        System.out.println("普通口罩....简单保护...请及时更换");
    }
}

N95Mask

/**
 * 具体产品
 */
public class N95Mask  extends AbstractMask{
    public N95Mask(){
        this.price = 2;
    }

    @Override
    public void protectedMe() {
        System.out.println("N95口罩....超级防护");
    }
}

MainTest

/**
 * 抽象出来。
 *      可以抽象成接口(只有方法),可以抽象成抽象类(有些属性也需要用)
 */
public class MainTest {

    public static void main(String[] args) {

        WulinFactory wulinFactory = new WulinWuHanMaskFactory();

        AbstractMask abstractMask = wulinFactory.newMask();
        abstractMask.protectedMe();


        wulinFactory = new WulinHangZhouMaskFactory();
        AbstractMask abstractMask1 = wulinFactory.newMask();
        abstractMask1.protectedMe();
        
        wulinFactory = new WulinRacingCarFactory();
        wulinFactory.newCar().run();
    }
}

image.png

6. 工厂模式的退化

当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式

7. 工厂模式优点

  1. 良好的封装性,代码结构清晰: 用户想要一个具体的产品对象,只需要知道这个产品的类名(约束字符串)即可,关于如何创建这个类,是不需要知道的,降低了模块间的耦合。
  2. 工厂方法模式的拓展性十分优秀: 只需要适当的修改一个工厂类或者拓展一个工厂类即可完成。
  3. 屏蔽产品类: 这个特点很重要,用户只需关心产品的接口,只要接口保持不变,系统的上层模块就不会发生变化。

举一个工厂方法的例子

如果使用JDBC连接数据库,数据库从MySQL切换到Oracle,需要改动的地方就是切换一下驱动名称(前提是SQL是标准语句),其他的都不要修改,这是工厂模式灵活的一个案例。

最后,工厂方法模式是典型的解耦框架,高层模块需要知道产品的抽象类,其他的实现类都不用担心,符合迪米特法则,我不需要的就不去交流,也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里氏替换原则,使用产品子类替换产品父类,没问题。

8. 抽象工厂模式优缺点

8.1 抽象工厂模式优点

  1. 封装性: 每个产品的实现类不是高层模块要关心的,关心的是接口,是抽象类。只要知道工厂类是谁,我们就能创造出需要的对象,省时省力
  2. 产品族内的约束为非公开状态

8.2 抽象工厂模式缺点

产品族拓展十分困难。因为我们要增加一个产品类C,既向产品族中多填一个工厂来创建C,因此又要天将很多的类。

再说说往一个已经实现的工厂类中添加一个方法,接着它的实现类都要去增加,严重违反了开闭原则

希望大家好好理解!!!