文档章节

Java设计模式学习之工厂模式

路小磊
 路小磊
发布于 07/21 23:22
字数 1967
阅读 2475
收藏 61

在Java(或者叫做面向对象语言)的世界中,工厂模式被广泛应用于项目中,也许你并没有听说过,不过也许你已经在使用了。 简单来说,工厂模式的出现源于增加程序序的可扩展性,降低耦合度。之所以叫做工厂模式,是用工厂生产产品来形象的比喻代码中生产对象的过程。总体来说,工厂模式分为以下几种:

  • 简单工厂模式(Simple Factory Pattern)
  • 工厂方法模式(Factory Method Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)

简单工厂模式(Simple Factory Pattern)

我们模拟一种场景,有一家汽车厂(AutoFactory)要生产汽车,现在主要生产小轿车(Car)和大巴车(Bus),那用代码模拟如下:

首先“设计”一个汽车原型(定义汽车接口),这个接口体现了所有汽车的共性:

public interface Auto {
	//所有汽车都可以被驾驶
	public void drive();
}

接下来我们“设计”两种汽车:小轿车和大巴车:

//小轿车
public class Car implements Auto{
	@Override
	public void drive(){
		System.out.println(“小轿车启动了”);
	}
}
//大巴车
public class Bus implements Auto{
	@Override
	public void drive(){
		System.out.println(“大巴车启动了”);
	}
}

开始“建厂”了,我们实现一个简单工厂类:

public class AutoFactory{
	//生产汽车
	public Auto produce(String name){
		if("car".equals(name)){
			return new Car();
		} else if("bus".equals(name)){
			return new Bus();
		}
	}
}

一切就绪,我们开始生产汽车了,先生产一辆小轿车:

AutoFactory factory = new AutoFactory();
Auto car = factory.produce("car");
car.drive();

简单工厂模式实现了生成产品类的代码跟具体的产品实现分离,在工厂类中你可以添加所需的生成产品的逻辑代码,但是问题来了,这不符合“开放-封闭”原则的,也就是说对扩展开放,对修改关闭,如果你要加一个新的汽车类型还需要修改produce方法,为解决这个问题,从而引入了工厂方法模式(Factory Method Pattern)。

工厂方法模式(Factory Method Pattern)

工厂为了扩大市场,现在要开始生产卡车(Truck)了,于是我们设计一辆卡车:

//卡车
public class Truck implements Auto{
	@Override
	public void drive(){
		System.out.println(“卡车启动了”);
	}
}

如果按照简单工厂的逻辑,需要修改produce方法(也就是我们要改造已有工厂),这样会影响已有生产,怎么办呢?解决办法是再新建新的工厂:

首先我们“设计”一个工厂原型(工厂接口):

public interface IAutoFactory{
	//生产汽车
	public Auto produce(String name);
}

然后将原来的工厂简单改造符合设计好的工厂原型(实现接口即可,所有逻辑不变):

public class AutoFactory implements IAutoFactory{
	//生产汽车
	@Override
	public Auto produce(String name){
		if("car".equals(name)){
			return new Car();
		} else if("bus".equals(name)){
			return new Bus();
		}
	}
}

好的,接下来为了生产卡车,我们要为卡车单独建厂:

public class TruckAutoFactory implements IAutoFactory{
	//生产卡车
	@Override
	public Auto produce(String name){
		return new Truck();
	}
}

开始生产卡车:

IAutoFactory factory = new TruckAutoFactory();
Auto car = factory.produce(null);
car.drive();

这里的抽象工厂中,我们为了减少改造成本,在简单工厂基础上做最小修改,理论上produce参数可以没有,然后为小轿车、大巴车和卡车分别建立工厂,分别生产。这样如果有了新的类型的车,可以不改动之前的代码,新建一个“工厂”即可,做到“开放封闭原则”。

虽然看似类变多了,逻辑复杂了,但是这种改造带来的好处也是显而易见的:不变动老的代码,通过新建工厂类完成新功能的添加,老功能不变,最大限度的避免动了老代码的逻辑导致引入新的bug。

工厂方法的结构图如下:

抽象工厂模式(Abstract Factory Pattern)

我们继续针对汽车工厂说明,由于接下来工厂需要继续扩大规模,开始涉足汽车配件,上层决定涉足汽车大灯业务,针对已有车型生产前大灯。但是如果按照工厂方法模式,需要再继续新建一批工厂,针对每种汽车再建N个工厂,考虑到成本和简单性,针对对已有汽车工厂改造。

首先“设计”大灯原型:

//大灯
public interface Light {
	//开灯
	public void turnOn();
}

再“设计”小轿车、大巴车和卡车大灯:

//小轿车大灯
public class CarLight implements Light{
	@Override
	public void tunOn(){
		System.out.println(“小轿车大灯亮了”);
	}
}
//大巴车大灯
public class BusLight implements Light{
	@Override
	public void tunOn(){
		System.out.println(“大巴车大灯亮了”);
	}
}
//卡车大灯
public class TruckLight implements Light{
	@Override
	public void tunOn(){
		System.out.println(“卡车大灯亮了”);
	}
}

接下来我们重新“设计”原有的汽车工厂(修改工厂接口或者抽象工厂类)

public interface IAutoFactory{
	//生产汽车
	public Auto produce();
	//生产大灯
	public Light produceLight();
}

好的,改造工厂,首先改造小轿车工厂:

public class CarAutoFactory implements IAutoFactory{
	//生产汽车
	@Override
	public Auto produce(){
		return new Car();
	}

	//生产车灯
	@Override
	public Light produceLight(){
		return new CarLight();
	}
}

改造大巴车工厂:

public class BusAutoFactory implements IAutoFactory{
	//生产汽车
	@Override
	public Auto produce(){
		return new Bus();
	}

	//生产车灯
	@Override
	public Light produceLight(){
		return new BusLight();
	}
}

改造卡车工厂:

public class TruckAutoFactory implements IAutoFactory{
	//生产汽车
	@Override
	public Auto produce(){
		return new Truck();
	}

	//生产车灯
	@Override
	public Light produceLight(){
		return new TruckLight();
	}
}

开始生产:

//生产小轿车和小轿车大灯
IAutoFactory factory = new CarAutoFactory();
Auto car = factory.produce();
car.drive();
Light light = factory.produceLight();
light.turnOn();
//生产大巴车和小大巴车大灯
IAutoFactory factory = new BusAutoFactory();
Auto bus = factory.produce();
bus.drive();
Light light = factory.produceLight();
light.turnOn();
//生产卡车和卡大灯
IAutoFactory factory = new TruckAutoFactory();
Auto truck = factory.produce();
truck.drive();
Light light = factory.produceLight();
light.turnOn();

抽象工厂模式中我们可以定义实现不止一个接口,一个工厂也可以生成不止一个产品类,抽象工厂模式较好的实现了“开放-封闭”原则,是三个模式中较为抽象,并具一般性的模式。

抽象工厂模式示意图如下:

参考资料

工厂模式在Hutool中的应用

Hutool中,Hutool-db模块为了简化和抽象连接池的创建,使用了工厂方法模式,首先定义了DSFactory

//数据源工厂
public abstract class DSFactory {
	//获取数据源
	public abstract DataSource getDataSource(String group);
}

然后分别创建了:HikariDSFactoryDruidDSFactoryTomcatDSFactoryDbcpDSFactoryC3p0DSFactory几种常见连接池的工厂实现,这样用户可以很容易的使用对应的连接池工厂创建需要的连接池数据源(DataSource)。

同样,用户也可以自己继承DSFactory实现抽象方法getDataSource来自定义数据源。

在此基础上,对于数据源工厂的创建,又使用了简单工厂模式,代码如下:

private static DSFactory doCreate(Setting setting) {
	try {
		return new HikariDSFactory(setting);
	} catch (NoClassDefFoundError e) {
		//ignore
	}
	try {
		return new DruidDSFactory(setting);
	} catch (NoClassDefFoundError e) {
		//ignore
	}
	try {
		return new TomcatDSFactory(setting);
	} catch (NoClassDefFoundError e) {
		//ignore
	}
	try {
		return new DbcpDSFactory(setting);
	} catch (NoClassDefFoundError e) {
		//ignore
	}
	try {
		return new C3p0DSFactory(setting);
	} catch (NoClassDefFoundError e) {
		//ignore
	}
	// 默认使用Hutool实现的简易连接池
	return new PooledDSFactory(setting);
}

通过try的方式,按照优先级尝试创建对应连接池的工厂类,如果用户没有引入对应连接池库,就会报NoClassDefFoundError异常,从而尝试创建下一个连接池工厂,依次类推,直到发现用户未引入任何连接池库,则使用Hutool默认的简单连接池PooledDSFactory。通过这种方式,简化了用户对连接池的选择配置。

© 著作权归作者所有

共有 人打赏支持
路小磊

路小磊

粉丝 334
博文 53
码字总数 40548
作品 5
乌海
程序员
私信 提问
加载中

评论(11)

s
stys35

引用来自“OSC_SmDtAU”的评论

纯粹误导人AutoFactory factory = new TruckAutoFactory();
IAutoFactory factory = new TruckAutoFactory();
路小磊
路小磊

引用来自“OSC_SmDtAU”的评论

纯粹误导人AutoFactory factory = new TruckAutoFactory();
属于笔误,已修正。感谢意见。
s
stys35
纯粹误导人AutoFactory factory = new TruckAutoFactory();
路小磊
路小磊

引用来自“妞妞的傻小孑”的评论

对工厂模式有了清晰的认识!
哈哈,写的时候我也是。
路小磊
路小磊

引用来自“飞趣社区创始人”的评论

真棒,我也一直在用hutool的jar包,感觉开发进度比以前方便很多
谢谢~~针对Hutool欢迎提供宝贵意见和issue
路小磊
路小磊

引用来自“行者__”的评论

Java 用模式来弥补语言设计上的滞后和不足
是滴。我觉得设计模式更多是从软件工程以及多人协作的角度考虑。
路小磊
路小磊

引用来自“loki_lan”的评论

这个try catch也是醉了
哈哈,是滴,被很多人吐槽。Hutool中的这块代码做了更新。
行者__
行者__
Java 用模式来弥补语言设计上的滞后和不足
飞趣社区创始人
飞趣社区创始人
真棒,我也一直在用hutool的jar包,感觉开发进度比以前方便很多
loki_lan
loki_lan
这个try catch也是醉了
设计模式15——Template Method设计模式

Template Method模板方法设计模式定义一个操作中算法的骨架,将具体步骤的执行延迟到子类中实现。Java中的抽象类就是使用了模板方法设计模式。模板方法设计模式结构如下: 以文档处理为例,T...

小米米儿小
2014/01/24
0
0
设计模式 2014-12-19

book: 阎宏《JAVA与模式》 架构设计栏目 http://blog.csdn.net/enterprise/column.html 概要: http://bbs.csdn.net/forums/Embeddeddriver 23种设计模式分别是: 1.单例模式 2.工厂方法模式...

jayronwang
2014/12/19
0
0
学了那么多年设计模式依然不会用!那可真蠢!

什么是设计模式? 设计模式(Design Pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决...

GitChat技术杂谈
10/26
0
0
关于spring是用注解好,还是用xml好?

最近学习了一下java的工厂设计模式,感觉工厂模式最大的优点和spring的IOC有些相像,比如我们为一个User接口写了多个实现,记为:UserImpl1、UserImpl2,可以很轻松的来回切换实现,对于工厂...

上帝爱众生
2015/05/19
435
6
简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别

转载:原地址http://www.cnblogs.com/zhangchenliang/p/3700820.html 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别 结合简单示例和UML图,讲解工厂模式简单原理。 一、引子 话说...

法斗斗
05/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

为什么要学习Python?这10个理由足够了!

摘要: 看完这十个理由,我决定买本python从入门到精通! 如果你定期关注现今的科技发展,那么你可能想知道我为什么要写这篇文章告诉人们学习Python?因为几年前我提倡Java而不是Python。 在...

阿里云官方博客
21分钟前
2
0
spring服务方式配置okhttp3

问题 如果把OKhttp以Spring服务方式配置,就解决了从配置中心运行时刷新配置参数的问题。 OkHttpConfig.java package com.zyl.config;import okhttp3.OkHttpClient;import org.springfra...

亚林瓜子
22分钟前
2
0
8张图让你一步步看清 async/await 和 promise 的执行顺序

**摘要:**面试必问 原文:8张图帮你一步步看清 async/await 和 promise 的执行顺序 作者:ziwei3749 Fundebug经授权转载,版权归原作者所有。 为什么写这篇文章? 说实话,关于js的异步执行顺...

Fundebug
22分钟前
1
0
Linux 命令菜单

#!/bin/bash #menu.sh menu(){ source ~/.bashrc echo "=================================" echo "Please enter your choise:" echo "(0) Kill all java" echo "(1) Start all tomcat" echo......

mellen
28分钟前
3
0
原来云数据库也是有思想的...

本文由一刻talks发表 邵宗文,腾讯云数据库专家副总监。十余年数据库从业经验,2009年加入腾讯,曾负责腾讯网,新闻客户端,快报,视频,财经,体育等数据库平台部署、规划及运维支持工作。本...

腾讯云加社区
29分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部