Java 设计模式学习之工厂模式
在Java(或者叫做面向对象语言)的世界中,工厂模式被广泛应用于项目中,也许你并没有听说过,不过也许你已经在使用了。 简单来说,工厂模式的出现源于增加程序序的可扩展性,降低耦合度。之所以叫做工厂模式,是用工厂生产产品来形象的比喻代码中生产对象的过程。总体来说,工厂模式分为以下几种:
简单工厂模式(Simple Factory Pattern)
工厂方法模式(Factory Method Pattern)
抽象工厂模式(Abstract Factory Pattern)
简单工厂模式(Simple Factory Pattern)
我们模拟一种场景,有一家汽车厂(AutoFactory)要生产汽车,现在主要生产小轿车(Car)和大巴车(Bus),那用代码模拟如下:
首先“设计”一个汽车原型(定义汽车接口),这个接口体现了所有汽车的共性:
接下来我们“设计”两种汽车:小轿车和大巴车:
开始“建厂”了,我们实现一个简单工厂类:
一切就绪,我们开始生产汽车了,先生产一辆小轿车:
简单工厂模式实现了生成产品类的代码跟具体的产品实现分离,在工厂类中你可以添加所需的生成产品的逻辑代码,但是问题来了,这不符合“开放-封闭”原则的,也就是说对扩展开放,对修改关闭,如果你要加一个新的汽车类型还需要修改produce方法,为解决这个问题,从而引入了工厂方法模式(Factory Method Pattern)。
工厂方法模式(Factory Method Pattern)
工厂为了扩大市场,现在要开始生产卡车(Truck)了,于是我们设计一辆卡车:
如果按照简单工厂的逻辑,需要修改produce方法(也就是我们要改造已有工厂),这样会影响已有生产,怎么办呢?解决办法是再新建新的工厂:
首先我们“设计”一个工厂原型(工厂接口):
然后将原来的工厂简单改造符合设计好的工厂原型(实现接口即可,所有逻辑不变):
好的,接下来为了生产卡车,我们要为卡车单独建厂:
开始生产卡车:
这里的抽象工厂中,我们为了减少改造成本,在简单工厂基础上做最小修改,理论上produce参数可以没有,然后为小轿车、大巴车和卡车分别建立工厂,分别生产。这样如果有了新的类型的车,可以不改动之前的代码,新建一个“工厂”即可,做到“开放封闭原则”。
虽然看似类变多了,逻辑复杂了,但是这种改造带来的好处也是显而易见的:不变动老的代码,通过新建工厂类完成新功能的添加,老功能不变,最大限度的避免动了老代码的逻辑导致引入新的bug。
工厂方法的结构图如下:
抽象工厂模式(Abstract Factory Pattern)
我们继续针对汽车工厂说明,由于接下来工厂需要继续扩大规模,开始涉足汽车配件,上层决定涉足汽车大灯业务,针对已有车型生产前大灯。但是如果按照工厂方法模式,需要再继续新建一批工厂,针对每种汽车再建N个工厂,考虑到成本和简单性,针对对已有汽车工厂改造。
首先“设计”大灯原型:
再“设计”小轿车、大巴车和卡车大灯:
接下来我们重新“设计”原有的汽车工厂(修改工厂接口或者抽象工厂类)
好的,改造工厂,首先改造小轿车工厂:
改造大巴车工厂:
改造卡车工厂:
开始生产:
抽象工厂模式中我们可以定义实现不止一个接口,一个工厂也可以生成不止一个产品类,抽象工厂模式较好的实现了“开放-封闭”原则,是三个模式中较为抽象,并具一般性的模式。
抽象工厂模式示意图如下:
参考资料
Java设计模式——工厂模式
结合实例分析简单工厂模式&工厂方法模式&抽象工厂模式的区别
工厂模式在Hutool中的应用
在Hutool中,Hutool-db模块为了简化和抽象连接池的创建,使用了工厂方法模式,首先定义了DSFactory:
然后分别创建了:HikariDSFactory、DruidDSFactory、TomcatDSFactory、DbcpDSFactory、C3p0DSFactory几种常见连接池的工厂实现,这样用户可以很容易的使用对应的连接池工厂创建需要的连接池数据源(DataSource)。
同样,用户也可以自己继承DSFactory实现抽象方法getDataSource来自定义数据源。
在此基础上,对于数据源工厂的创建,又使用了简单工厂模式,代码如下:
通过try的方式,按照优先级尝试创建对应连接池的工厂类,如果用户没有引入对应连接池库,就会报NoClassDefFoundError异常,从而尝试创建下一个连接池工厂,依次类推,直到发现用户未引入任何连接池库,则使用Hutool默认的简单连接池PooledDSFactory。通过这种方式,简化了用户对连接池的选择配置。
来源:https://my.oschina.net/looly/blog/1860776
版权声明:文章来源网络,版权归作者本人所有,如侵犯到原作者权益,请与我们联系删除或授权事宜