JAVA:工厂模式(Factory Pattern)的技术指南

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一,它通过定义一个创建对象的接口来让子类决定实例化哪个类,使得创建对象的过程更加灵活和可扩展。本文将详细介绍工厂模式的概念、类型以及实际应用示例。

设计模式样例:https://gitee.com/lhdxhl/design-pattern-example.git

工厂模式是一种创建型设计模式,主要用来封装对象的创建过程。它将实例化对象的代码从使用者中分离出来,遵循 \”开放-关闭原则\” 和 \”单一职责原则\”。

常见的工厂模式分为三种类型:

[微风] 简单工厂模式(Simple Factory)

[微风] 工厂方法模式(Factory Method)

​[微风] 抽象工厂模式(Abstract Factory)

​[微风] 封装性好:创建逻辑集中在工厂类中,简化了客户端代码。

​[微风] 可扩展性强:新增产品类时,只需扩展工厂类即可。

​[微风] 减少耦合:客户端代码与具体产品类解耦。

简单工厂模式是最基本的工厂模式,通过一个工厂类,根据传入的参数来决定创建哪种具体对象。假设我们需要一个形状工厂,用于创建不同的形状对象。

输出:

工厂方法模式通过定义一个抽象工厂接口,将对象的创建过程延迟到子类实现。相比简单工厂模式,工厂方法模式符合开闭原则。

输出:

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。它是一种工厂的工厂。

输出:

​[微风] 日志框架:如 SLF4J 中的 Logger 工厂。

​[微风] 数据库连接:如 JDBC 中的 `DriverManager.getConnection()`。

​[微风] XML 解析:如 DOM 和 SAX 的解析器工厂。

​[微风] Spring 框架:如 BeanFactory 和 ApplicationContext。

工厂模式是 Java 开发中不可或缺的设计模式,能够显著提高代码的可扩展性和可维护性。在实际开发中,根据需求选择合适的工厂模式能够有效解决对象创建的复杂性问题。

希望本文对您理解工厂模式有所帮助!如果有任何问题,欢迎讨论交流!

干货分享:什么是Java设计三大工厂模式?

本文主要会介绍三种工厂模式:简单工厂,工厂方法,抽象工厂。其中简单工厂并不属于 GoF 23 种设计模式,工厂方法和抽象工厂模式则是属于 GoF 23 种设计模式之中的 2 种。工厂模式作为一种非常常用的设计模式,在日常开发中非常常见,也是一种非常基础的设计模式。

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式
  • 三种工厂模式对比
  • 工厂模式能解决什么问题

简单工厂设计模式:Simple Factory Pattern,指的是由一个工厂对象来决定创建具体的产品实例,简单工厂模式并不属于 GoF 23 种设计模式之一,但是我们在平常开发中也运用得非常广泛。

示例下面我们就农场里面种植水果来举例看看简单工厂模式该怎么写(这里我们需要新建一个 simple 目录,相关类创建在 simple 目录下)。

  • 新建一个产品接口 IProduct.java,接口中定义了一个种植方法。
  • 新建一个苹果类 Apple.java 来实现产品接口。
  • 新建一个桔子类 Orange.java 来实现产品接口。

如果不用工厂模式那么创建 Apple 和 Orange 对象都直接 new 一个出来就好了,但是这种方式很不友好,一旦一个对象的创建非常复杂,那么会非常不方便,所以需要一个工厂来帮助我们创建具体的产品类,从而隐藏创建细节。

  • 新建一个简单工厂类 SimpleFactory.java 来创建产品,其中定义了一个创建方法,根据产品类型来决定创建哪种产品。
  • 新建一个测试类 TestSimpleFactory.java 来测试一下。

接下来我们需要先执行 javac simple/*.java 命令进行编译。然后再执行 java simple.TestSimpleFactory 命令运行测试类(大家一定要自己动手运行哦,只有自己实际去运行了才会更能体会其中的思想)。

这时候我们就将创建细节隐藏了,全部产品都通过 SimpleFactory 来帮忙创建。但是这种写法仍然存在两个问题:

假如我调用 createProduct 方法参数写错了,比如 apple 写成了 aple,这时候代码编译可以通过,运行的时候才能发现问题。如果产品很多,那么 SimpleFactory 类中会产生大量的 if 分支。所以为了解决上面的两个问题,我们可以再优化一下 SimpleFactory 类中的 createProduct 方法。

改造一下 SimpleFactory 类,新增一个 createProduct2 方法。

  • 同样的,我们再重新建立一个测试类 TestSimpleFactory2.java,改成调用 createProduct2方法来获取产品对象。

同样的我们需要再执行 javac simple/*.java 命令进行编译。然后再执行 java simple.TestSimpleFactory2 命令运行测试类(大家一定要自己动手运行哦,只有自己实际去运行了才会更能体会其中的思想)。

可以看到,这种写法完美地解决了上面存在的两个问题(不过一般我们的工厂类都会将创建对象实例的方法设置成静态方法)。

简单工厂模式适用场景简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。

简单工厂模式存在的问题假如每种产品创建不仅仅只是实例化一个对象,还有其它逻辑需要处理,那么我们无法直接使用一句反射语句来创建对象,所以还是避免不了要写很多 if 或者 switch 循环分支。这样每新增一个产品我们都需要修改简单工厂类,违背了开闭原则,而且随着产品越来越丰富,工厂的职责会变得越来越多,久而久之会越来越难以维护。

为了弥补简单工厂方法的不足之处,所以就有了工厂方法模式。

工厂方法模式:Fatory Method Pattern,主要用来解决简单工厂模式存在的问题。其是指定义一个创建对象的接口,然后创建不同的具体工厂来创建对应的产品。工厂方法让类的实例化推迟到工厂子类中进行,在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节。

工厂方法模式中假如需要新增产品,只需要再新建工厂实现类,无需修改源码,符合开闭原则。示例我们还是以上面农场种植水果举例进行说明,产品接口和产品类不做修改,为了方便大家练习的时候对照,所以我还是把产品接口和产品类在下面重写一下(这里我们需要新建一个 method 目录,相关类创建在 method 目录下)。

  • 新建一个产品接口 IProduct.java。
  • 新建一个具体产品苹果类 Apple.java。
  • 新建一个具体产品桔子类 Orange.java 。

现在我们需要将工厂也抽象化,新建一个工厂接口 IFarmFactory.java,定义一个 create 方法,这个方法的返回值就是产品。

新建一个生产苹果的具体工厂类 AppleFactory.java,并实现工厂接口 IFarmFactory。

新建一个生产桔子的具体工厂类 OrangeFactory.java,并实现工厂接口 IFarmFactory。

到这里大家应该很明白工厂方法和简单工厂的区别了,简单工厂就是所有产品都由一个工厂类一个方法来创建,而工厂方法将工厂的职责也进行细化了,每种产品都由自己特定的工厂来生产,这也是单一职责原则的体现。

最后新建一个测试类 TestFactoryMethod.java 来进行测试。

接下来我们需要先执行 javac method/*.java 命令进行编译。然后再执行

  • java method.TestFactoryMethod

命令运行测试类(大家一定要自己动手运行哦,只有自己实际去运行了才会更能体会其中的思想)。

这时候如果需要新增其它商品,需要创建两个类:一个具体产品类,一个具体工厂类,所以说灵活的同时付出的代价就是类的数量变多了,学习到后面大家就知道,这也是设计模式的共性。

工厂方法模式的适用场景工厂方法模式主要适用于以下场景:

  • 创建对象需要大量重复的代码。
  • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
  • 一个类通过其子类来指定创建哪个对象。

工厂方法模式的缺点工厂方法模式的缺点也是很明显的,每新增一个产品就需要新增两个类,一旦产品数量上来了,类的个数也会过多,就会增加了系统的复杂度,也使得系统更加抽象难以理解。

抽象工厂模式:Abstract Factory Pattern,是指提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。

抽象工厂模式强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象时需要大量重复的代码。此时我们就需要提供一个产品类的库,使得所有的产品以同样的接口出现,这样客户端就可以不依赖于具体实现。

什么是产品族在学习抽象工厂模式之前,我们需要先了解一下什么叫产品族。产品族指的就是相似的产品,比如说我们常用的手机,有华为、小米、OPPO,这些不同品牌的手机就属于同一个产品族,它们隶属于不同的公司,也就是需要由不同的工厂进行生产,这些工厂都可以共用同一个抽象方法来生产手机,这就是抽象工厂模式的本质,将相似的产品(同一产品族)抽象出公共的方法,统一对外接口。

示例接下来我们还是以农场种植水果举例进行说明。为了方便举例,我们只将水果和农场分为南北两个品种,比如南方农场生产的苹果和桔子称之为南方苹果和南方桔子,而北方农场生产的苹果和桔子就称之为北方苹果和北方桔子(这里我们需要新建一个 abstractFactory 目录,相关类创建在 abstractFactory 目录下)。

  • 新建一个苹果的接口 IApple.java,定义一个种植苹果的方法。
  • 新建一个具体产品“南方苹果”类 SouthApple.java 来实现 IApple 接口。
  • 新建一个桔子的接口 IOrange.java,定义一个种植桔子的方法。
  • 新建一个具体产品“南方桔子”类 SouthOrange.java 来实现 IOrange 接口。

以上就是一个将产品抽象化的过程,接下来我们就需要将产品交给工厂进行创建。

  • 新建一个抽象工厂接口 IFactory.java,定义两个方法:一个用来创建苹果对象,一个用来创建桔子对象。
  • 新建一个具体工厂“南方工厂”类 SouthFarmFactory.java 来实现 IFactory接口,并实现其中的两个抽象方法。
  • 现在我们可以新建一个测试类 TestAbstractFactory.java 来进行测试。
  • 接下来我们需要先执行 javac abstractFactory/*.java 命令进行编译。然后再执行 java abstractFactory.TestAbstractFactory 命令运行测试类。

这就是一个抽象工厂的设计模式示例,不过上面我并没有完成北方农场的示例,这个就作为本次实验留给大家的作业,大家可以自己把北方农场生产北方苹果和北方桔子的类完善了并进行测试,自己动手才能加深印象。

假如这时候又有一个新的农场要建立生产一样的产品,那么就可以再新建一个对应的产品类和对应的工厂类就可以实现了。

抽象工厂模式的适用场景抽象工厂模式适用于我们有一系列类似的产品(比如上面的南方苹果和北方苹果,还有华为手机和小米手机),然后这些产品的实现又有细节上的不同,那么这时候就可以利用抽象工厂模式来将产品进行抽象化。

抽象工厂模式的缺点根据上面的例子再结合设计模式七大原则,其实我们可以发现抽象工厂有一个很大的缺点,那就是扩展产品相当困难,比如示例中现在农场想种植西瓜,那么我们需要修改工厂的源码,新增种植西瓜的方法,这样的话抽象工厂、具体工厂都需要修改,显然违背了开闭原则。所以抽象工厂模式使用的前提必须是产品比较稳定,不会轻易作出修改,否则后期的维护将会非常困难。

工厂模式只是一个统称,大部分人都知道工厂模式,但是却并不是所有人都知道工厂模式也分为了 3 种。在实际开发过程中,当我们需要隐藏对象的创建细节时,可以考虑使用工厂模式,但是却更应该根据实际业务场景,选择一种比较合适的工厂模式。参考资料:https://www.lanqiao.cn/courses/3031

如果您觉得这篇文章对你有帮助就点个赞吧!关注我们收获更多编程好课和实用干货!

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。