工厂模式简介(一):简单工厂模式

现今在互联网圈,设计模式并不是那么容易被提起了,这恐怕和互联网的快速迭代和微服务的流行有一些关系。设计模式在函数式编程火热的时候还一度成为了 anti-pattern,被大家觉得古板、无用。当然,在这股函数式编程热潮中中枪的可能是面向对象编程,设计模式是作为面向对象编程中的精华而遭到了唾弃。

实际上再回过头想一下,这些设计模式是实际开发中提炼出的有用经验,在一定程度上确实可以提高程序的可读性和可扩展性;另一方面,设计模式作为固定的套路,也加深了代码在作者和读者之间理解的程度,在这个意义上,它可以作为一种沟通的媒介。当然,前提是在正确的场景下使用。所谓正确的场景,就是合适的场景,并非为了使用而生搬硬套,而是确实解决了某些问题。

这篇文章里,我来简单介绍一下一种最常见的设计模式:工厂模式,谈谈我对这个模式的理解。

介绍

工厂模式可能是 Java 中使用最多的设计模式之一。它属于对象创建模式。在工厂模式中,我们通过工厂来创建对象,隐藏创建对象的逻辑,并使用公共的接口将这个对象暴露给客户端。

我们先来看最简单的一种工厂模式。

简单工厂

绝大部分日常代码工作中,简单工厂就足够我们使用。它适用于我们想通过一个工厂类来封装某一个产品类别(即想创建实例的类)的创建逻辑时。且这个产品类有可能有多种子类型,但是调用方并不关心具体是哪种类型,而是希望通过传递一定的参数信息,来告知工厂来选择合适的子类型并创建。

下面举个实际的例子。

假设我们有一个产品类别叫 Car,代表汽车。每个汽车厂商都能生产不同品牌的 Car,我们把这些不同品牌的 Car 看作 Car 的子类。这样,我们可以有 BmwCarVolvoCarTeslaCar 等等,如下图所示。

假设有一个神奇的万能造车工厂,叫做 CarFactory ,它可以生产多种品牌的汽车,也就是说既可以生产 BmwCar 还能生产 VolvoCar 和 TeslaCar 。当我们想生产某种 Car 时,我只需要告诉这个神奇的工厂 CarFactory,我想要什么牌子的汽车,它就能负责把它生产出来。我不需要关心它具体是怎么生产的,它最后只需要交付给我一个满足需求的 Car 即可。

我们作为这个工厂的客户,该如何告诉 CarFactory 生产什么牌子的汽车呢?可以通过参数传递给 CarFactory 的 createCar() 方法。例如:

createCar() 方法中,可以根据传入的参数进行选择最终需要生产的类型:

完整代码示例,请参考代码仓库:https://github.com/gdong42/factory-pattern

这种模式中,调用方不用关心所需要的实际类型是什么,只需提供相应的类型信息即可。这种方式方便了调用方,将调用的客户端逻辑和具体实现类的构造逻辑在一定程度上解耦了开来。

那么这种模式有什么缺陷呢?从实际出发考虑,现实生活中很少有这种超级工厂,原因是这个工厂需要了解所有具体的产品的生产方式,不太实际。面向对象的软件工程反映实际世界,代码中也是一样,这个工厂类拥有所有产品的生产逻辑。每当我们需要增加一种产品类型时,都需要修改 createCar 方法。这显然不太理想。

另外,SimpleCarFactory 这个工厂类因为需要包含所有 Car 的生产逻辑,它必须依赖所有的类型。这导致客户端代码耦合所有的可选产品类型,而这些产品类型的依赖调用端可能永远也不需要使用。假设我们将各种具体产品类型和它们相关的实现类分别打包成为独立模块,则这个超级工厂需要依赖所有的模块。而我们希望的是,当我们生产某种特定的产品类型时,提供相应的实现的模块依赖即可。

如何基于这种方式改进解决这些问题呢?我们在下一篇工厂方法中聊聊这个问题。

 

Gan Dong

I'm a software programmer. Loving coding, music. And life.