导言

今天咱们来继续学习创立型规划形式中的工厂形式。在软件开发中,工厂形式是一种常见的规划形式,旨在供给一种灵活、可扩展的方式来创立目标实例。工厂形式一般分为简略工厂形式和笼统工厂形式两种首要形式,它们在不同情境下各具优势,能够帮助开发人员更好地管理目标的创立进程,并提高代码的可维护性和可扩展性。

本篇文章,咱们换个新思路来叙述(后续文章都按照此思路来):

  • 举比如叙述从无形式 ==> 简略工厂形式 ==> 笼统工厂形式的运用。
  • 探索 Spring 框架中对工厂形式的运用。
  • 从零开端填充咱们的规划百宝箱,包括面向目标根底面向目标规划准则面向目标规划形式
  • 针对工厂形式,咱们产生了哪些考虑?有什么问题?它们的答案是什么?

一、新能源轿车的开展

最近几年,新能源电车异军突起,掀起来又一条经济赛道!各大公司都进军这条赛道,建造不同品牌的新能源电车。今天咱们就以这条事例来叙述下工厂形式。

1、无形式情况下

假如不引进任何规划形式的话,咱们完成用户买车,厂商进行制造的流程应该是下面这姿态的:

package com.markus.desgin.mode.creational.factory.none;
/**
 * @author: markus
 * @date: 2024/3/16 9:59 PM
 * @Description: 无形式
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class NonePatterClient {
    public static void main(String[] args) {
        // 买小米轿车
        Car car = orderCar("xiaomi");
        // 买比亚迪轿车
        car = orderCar("byd");
    }
    private static Car orderCar(String type) {
        Car car;
        if ("xiaomi".equals(type)) {
            car = new XiaoMiCar();
        } else if ("byd".equals(type)) {
            car = new XiaoMiCar();
        } else {
            throw new UnsupportedOperationException("不支撑的轿车类型");
        }
        // 有了轿车厂商后,咱们就开端装置对应的电池、轮子以及座椅(实践上许多程序,我这儿就选三个作为举例)
        car.installBattery();
        car.installWheel();
        car.installSeat();
        // 将成品交给
        return car;
    }
}

接下来咱们考虑一下上述这段代码有什么问题?

显而易见,假如运用支撑更多的轿车类型,orderCar() 办法就会不断的被修改。这不符合规划准则中的开闭准则(对扩展敞开,对修改关闭)。

那么,咱们怎么改造一下上述代码呢?

2、简略工厂形式

在进行任何程序规划时,咱们想要做到对扩展敞开、对修改关闭的意图就只需要记住一点:剖析程序变化和不变化的部分,将变化的分布抽离出去。

好了,记住上述理论后,咱们开端着手对上述代码进行改造。

第一步:哪些是变化的部分?哪些是不变的部分?

重读 Java 规划形式: 深入探讨工厂形式,创立目标的灵活性与可维护性

第二步:将变化的部分抽离出去。

package com.markus.desgin.mode.creational.factory.article;
/**
 * @author: markus
 * @date: 2024/3/16 10:29 PM
 * @Description: 默许的轿车工厂
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class DefaultCarFactory implements CarFactory {
    @Override
    public Car createCar(CarType carType) {
        if (carType.equals(CarType.XIAOMI)) {
            return new XiaoMiCar();
        } else if (carType.equals(CarType.BYD)) {
            return new BYDCar();
        }
        throw new UnsupportedOperationException("其他轿车类型不支撑创立!");
    }
}

第三步:将原有代码进行终究改造。

package com.markus.desgin.mode.creational.factory.article;
/**
 * @author: markus
 * @date: 2024/3/16 10:37 PM
 * @Description: 简略工厂形式
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class SimpleFactoryPattern {
    public static void main(String[] args) {
        // 买小米轿车
        Car car = orderCar(CarType.XIAOMI);
        // 买比亚迪轿车
        car = orderCar(CarType.BYD);
    }
    private static Car orderCar(CarType carType) {
        CarFactory carFactory = new DefaultCarFactory();
        Car car = carFactory.createCar(carType);
        // 有了轿车厂商后,咱们就开端装置对应的电池、轮子以及座椅(实践上许多程序,我这儿就选三个作为举例)
        car.installBattery();
        car.installWheel();
        car.installSeat();
        // 将成品交给
        return car;
    }
}

能够看出,不论后续再呈现什么类型的轿车,orderCar() 办法的代码都不会进行修改,只需要在 DefaultCarFactory 类中进行扩展即可。

咱们可能会说了:这不便是挪了个当地吗?

对,便是搬到了另一个当地,可是别忘了咱们将这块的代码从客户端中笼统出来,它就能够服务于多个客户了,而不仅仅是当前这一个客户端。别的还有一个比较常见的问题:有些场景会把工厂办法界说为一个静态的办法。这是一个很常见的技巧,但这种与咱们上述完成的方式对比有一个比较明显的下风便是它不能经过承继来改变创立办法的行为。

到此咱们就完成经过简略工厂办法规划对代码进行了必定的改造,使其具有更好的可扩展性。实践上,它并不是一个规划形式,反而像一种编程习气,它界说了一个创立目标的接口,但由子类决定要实例化的类是哪一个。工厂办法让类把实例化推迟到子类。

最后用一张 UML 图来展示下工厂办法的运用:

重读 Java 规划形式: 深入探讨工厂形式,创立目标的灵活性与可维护性

此刻,又呈现了一种场景:每个轿车制造商觉得自己出产电池太困难,没有那么多精力投入,因此将电池的出产交给各个电池出产厂商进行出产,终究自己来完成组装。

3、笼统工厂形式

3.1 轿车

接口界说

package com.markus.desgin.mode.creational.factory.article.abstractfactory;
/**
 * @author: markus
 * @date: 2024/3/16 10:00 PM
 * @Description:
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public interface Car {
    void installWheel();
    void installSeat();
    void installBattery();
}

小米根底版轿车

package com.markus.desgin.mode.creational.factory.article.abstractfactory;
import com.markus.desgin.mode.creational.factory.article.battery.BatteryFactory;
/**
 * @author: markus
 * @date: 2024/3/16 11:29 PM
 * @Description:
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class XiaomiBasicCar extends AbstractCar {
    public XiaomiBasicCar(BatteryFactory batteryFactory) {
        super(batteryFactory);
    }
    @Override
    public void installWheel() {
        System.out.println("装置小米根底版轮子");
    }
    @Override
    public void installSeat() {
        System.out.println("装置小米根底版座椅");
    }
}

小米旗舰版轿车

package com.markus.desgin.mode.creational.factory.article.abstractfactory;
import com.markus.desgin.mode.creational.factory.article.battery.BatteryFactory;
/**
 * @author: markus
 * @date: 2024/3/16 11:29 PM
 * @Description:
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class XiaomiFlagshipCar extends AbstractCar {
    public XiaomiFlagshipCar(BatteryFactory batteryFactory) {
        super(batteryFactory);
    }
    @Override
    public void installWheel() {
        System.out.println("装置小米旗舰版轮子");
    }
    @Override
    public void installSeat() {
        System.out.println("装置小米旗舰版座椅");
    }
}

比亚迪根底版轿车

package com.markus.desgin.mode.creational.factory.article.abstractfactory;
import com.markus.desgin.mode.creational.factory.article.battery.BatteryFactory;
/**
 * @author: markus
 * @date: 2024/3/16 11:29 PM
 * @Description:
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class BYDBasicCar extends AbstractCar {
    public BYDBasicCar(BatteryFactory batteryFactory) {
        super(batteryFactory);
    }
    @Override
    public void installWheel() {
        System.out.println("装置比亚迪根底版轮子");
    }
    @Override
    public void installSeat() {
        System.out.println("装置比亚迪根底版座椅");
    }
}

比亚迪旗舰版轿车

package com.markus.desgin.mode.creational.factory.article.abstractfactory;
import com.markus.desgin.mode.creational.factory.article.battery.BatteryFactory;
/**
 * @author: markus
 * @date: 2024/3/16 11:29 PM
 * @Description:
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class BYDFlagshipCar extends AbstractCar {
    public BYDFlagshipCar(BatteryFactory batteryFactory) {
        super(batteryFactory);
    }
    @Override
    public void installWheel() {
        System.out.println("装置比亚迪旗舰版轮子");
    }
    @Override
    public void installSeat() {
        System.out.println("装置比亚迪旗舰版座椅");
    }
}

3.2 电池制造厂界说

package com.markus.desgin.mode.creational.factory.article.battery;
/**
 * @author: markus
 * @date: 2024/3/16 11:05 PM
 * @Description:
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public interface BatteryFactory {
    String productBattery();
}

宁德年代

package com.markus.desgin.mode.creational.factory.article.battery;
/**
 * @author: markus
 * @date: 2024/3/16 11:05 PM
 * @Description: 宁德年代
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class CATL implements BatteryFactory {
    @Override
    public String productBattery() {
        return "宁德年代电池";
    }
}

东芝

package com.markus.desgin.mode.creational.factory.article.battery;
/**
 * @author: markus
 * @date: 2024/3/16 11:06 PM
 * @Description: 东芝
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class Toshiba implements BatteryFactory {
    @Override
    public String productBattery() {
        return "东芝电池";
    }
}

3.3 轿车制造厂界说

小米工厂

package com.markus.desgin.mode.creational.factory.article.abstractfactory;
import com.markus.desgin.mode.creational.factory.article.battery.BatteryFactory;
import com.markus.desgin.mode.creational.factory.article.battery.CATL;
import com.markus.desgin.mode.creational.factory.article.battery.Toshiba;
/**
 * @author: markus
 * @date: 2024/3/16 11:25 PM
 * @Description:
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class XiaomiCarFactory extends AbstractCarFactory {
    @Override
    protected Car createCar(CarType carType) {
        BatteryFactory batteryFactory = new Toshiba();
        if (CarType.BASIC.equals(carType)) {
            return new XiaomiBasicCar(batteryFactory);
        } else if (CarType.FLAGSHIP.equals(carType)) {
            return new XiaomiFlagshipCar(batteryFactory);
        }
        throw new UnsupportedOperationException("不支撑的轿车类型");
    }
}

比亚迪工厂

package com.markus.desgin.mode.creational.factory.article.abstractfactory;
import com.markus.desgin.mode.creational.factory.article.battery.BatteryFactory;
import com.markus.desgin.mode.creational.factory.article.battery.CATL;
import com.markus.desgin.mode.creational.factory.article.battery.Toshiba;
/**
 * @author: markus
 * @date: 2024/3/16 11:32 PM
 * @Description: 比亚迪轿车出产商
 * @Blog: https://markuszhang.com
 * It's my honor to share what I've learned with you!
 */
public class BYDCarFactory extends AbstractCarFactory {
    @Override
    protected Car createCar(CarType carType) {
        BatteryFactory batteryFactory = new CATL();
        Car car;
        if (CarType.BASIC.equals(carType)) {
            return new BYDBasicCar(batteryFactory);
        } else if (CarType.FLAGSHIP.equals(carType)) {
            return new BYDFlagshipCar(batteryFactory);
        }
        throw new UnsupportedOperationException("不支撑的轿车类型");
    }
}

3.4 咱们做了些什么?

相较于简略工厂,咱们面对电池出产困难,轿车出产商将电池的出产交给详细的电池制造商这样一个问题,经过引进电池出产工厂 BatteryFactory来处理这一问题。运用这个接口书写代码,咱们能够将电池的出产与实践的轿车出产解耦,以便在不同的轿车厂商(或许同一厂商下不同轿车类型中)运用不同的电池制造出不同的轿车。由于代码从实践的产品中解耦,所以咱们能够替换不同的工厂来获得不同的行为。

上述形式便是笼统工厂形式,它供给一个接口,用于创立相关或依靠目标的宗族而不需要清晰指定详细类。咱们来看下它的 UML 图(比较复杂)

重读 Java 规划形式: 深入探讨工厂形式,创立目标的灵活性与可维护性

二、工厂形式在 Spring 中的运用

工厂形式在 Spring 中运用到许多当地,这儿举两个比如:

  • BeanFactory,它便是一个巨大的出产 Bean 的工厂,客户端经过 BeanFactory#getBean 来获取相应的 Bean 实例,而无需重视 Bean 怎么被创立的。
  • 假如咱们看过 Spring AOP 源码的话,必定对 AopProxyFactory 感到了解,它的职责便是出产 AopProxy,而不同 AopProxy 又会创立详细的署理目标。
    • 重读 Java 规划形式: 深入探讨工厂形式,创立目标的灵活性与可维护性

三、规划形式百宝箱

在本节,咱们开端填充咱们的百宝箱:

  • 面向目标根底
  • 面向目标准则
    • 依靠笼统,不要依靠详细类
    • 针对接口编程,不针对详细完成编程
    • 类应该对扩展敞开,对修改关闭
    • 为交互目标之间的松耦合规划而努力
  • 面向目标规划形式
    • 简略工厂形式:界说了一个创立目标的接口,将创立目标的内容从客户端抽离出来
    • 笼统工厂形式:供给一个接口,用于创立相关或依靠目标的宗族,而不需要清晰指定详细类

四、本文总结

好了,总结一下,在本篇的学习傍边,咱们能够总结出以下知识点:

  • 一切的工厂都是用来封装目标的创立。
  • 简略工厂,尽管不是真实的规划形式,但仍不失为一个简略的办法,能够将客户程序从详细类解耦。
  • 笼统工厂运用目标组合:目标的创立被完成在工厂接口所暴露出来的办法中。
  • 一切工厂形式都经过减少运用程序和详细类之间的依靠促进松耦合。
  • 笼统工厂创立相关的目标宗族,而不需要依靠他们的详细类。
  • 依靠倒置准则,知道咱们防止依靠详细类型,而要尽量依靠笼统。
  • 工厂是很有威力的技巧,帮助咱们针对笼统编程,而不要针对详细类编程。