前言
在项目中经常会碰到工厂模式,不光在项目中有在阅读源码的时候也一定少不了工厂模式。在我们上上一篇文章分布式定时任务Quartz中创建触发器也是通过Quartz所提供的工厂来创建实例。可见工厂模式有多方便多常用。本文主要讲解简单工厂模式。
工厂模式[1](Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
介绍
工厂模式有三种分为简单工厂模式、厂方法模式、抽象工厂模式其中简单工厂模式并不属于GOF[2]所提出的23种设计模式之中,简单工厂模式其实更像是一种习惯。在设计模式之中工厂模式是属于创建型。
简单工厂模式
定义
简单工厂模式到底啥时候使用,还有就是为什么要使用简单工厂模式呢?
首先在上面我们说了工厂模式是创建型,在介绍的时候也说了它提供了一种创建对象的最佳方式
也就是说简单工厂模式的定义就是由一个工厂对象来决定创建那种产品实例。其次就是什么时候使用简单工厂模式,首先现在有这样一个场景。小明决定去卖车,一种是奔驰一种是奥迪:
/**
* 小明要卖车
*/
/**
* 先生产奥迪
*/
AudiCar audiCar = new AudiCar();
/**
* 在生产奔驰
*/
MercedesCar mercedesCar = new MercedesCar();
然后发现自己生产成本太高,小明还要自己盯着各种细节。这并不是小明想要的他只想赚个差价。这个时候就可以使用简单工厂模式来帮助小明因为创建的对象比较少,然后工厂只需要知道需要什么就返回什么然后也不需要关心关键逻辑的时候就可以使用简单工厂模式
这就是简单工厂模式的使用场景,那我使用了简单工厂模式有啥优点呢?从上面简单的例子就可以知道客户端可以免除创建对象的责任直接交给工厂进行创建
然后就是只需要知道传入的参数就可以获取到所需要的参数而且无需知道创建细节
这不正是小明想要的吗?hahaha。注意:在强调一下简单工厂模式并不属于23种设计模式,它只是一种编码风格和实现
案例
看完上面你就已经知道什么时候用简单工厂模式还有就是知道了它的优点和使用场景,那么现在就开始实战。在创建之前要知道简单工厂模式有以下几种角色。
然后定义一个抽象产品接口。
代码语言:javascript复制/**
* @Author :luomengsun.
* @Date :Created in 13:26 2020/1/5
* @Description:
*/
public interface Car {
/**
* 输出简单信息
*/
void printInfo();
}
一开始定义的Audi和Mercedes就是我们的具体产品,改造一下
代码语言:javascript复制public class AudiCar implements Car {
@Override
public void printInfo() {
System.out.println("生产了奥迪");
}
}
public class MercedesCar implements Car{
@Override
public void printInfo() {
System.out.println("生产了奔驰");
}
}
它们都实现了我们的抽象产品接口(也可以使用抽象类,但是尽量使用面向接口),现在定义工厂类。
代码语言:javascript复制public class CarFactory {
public Car getCarFactory(String str){
Car car = null;
if("audi".endsWith(str)){
car = new AudiCar();
}else if("mercedes".equals(str)){
car = new MercedesCar();
}else {
System.out.println("没有定义产品");
}
return car;
}
}
然后我们就在测试客户端里面通过工厂类来创建汽车。
代码语言:javascript复制public class TestClient {
public static void main(String[] args) {
/**
* 小明通过汽车工厂生产车
*/
CarFactory carFactory = new CarFactory();
/**
* 先生产奥迪
*/
Car car = carFactory.getCarFactory("audi");
car.printInfo();
}
}
这个时候控制台输出生产了奥迪
。UML类图:
对比
上面就实现了简单工厂模式,我们对比一下最开始的实现,在引入简单工厂模式之后客户端需要什么就直接告诉工厂就行,根本不需要我们关心具体的细,实质上也就是对创建对象进行了封装。如果在举一个例子的话就比如我们去肯德基去吃饭,我们想要吃薯条直接在前台点就行,你会关心薯条是怎么生产的吗?而且在你点薯条之前你肯定是知道有这个产品的,不然你怎么去下单?
缺点
上面把简单工厂模式夸了一大堆,那它都有啥缺点呢?你别说缺点还真的有,首先看一下我们的工厂类。
代码语言:javascript复制public class CarFactory {
public Car getCarFactory(String str){
Car car = null;
if("audi".endsWith(str)){
car = new AudiCar();
}else if("mercedes".equals(str)){
car = new MercedesCar();
}else {
System.out.println("没有定义产品");
}
return car;
}
}
如果这个时候我想要增加宝马怎么办,肯定要先创建一个具体产品,然后在修改工厂类的判断逻辑,这样就违反了开闭原则。而且工厂类集中了所有实例的创建逻辑,违反了高内聚低耦合的原则。 那么有没有一种方法可以不修改工厂类里面的逻辑的方法吗?这个肯定是有的,我们可以使用反射来创建具体的产品。修改一下工厂类:
代码语言:javascript复制public class CarFactory {
public Car getCarFactory(Class c){
Car car = null;
try {
car = (Car) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return car;
}
}
代码实例
上面清楚了简单工厂模式接下来看一下简单工厂模式实际的运用。 在JDK中处理时间不光有Date这个类还有Calendar类,在Calendar类中就使用了简单工厂模式。看一下getInstance()方法里面的实现
代码语言:javascript复制 public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
它在里面调用了createCalendar
方法然后在createCalendar
方法里面有以下实现,是不是很熟悉
这里就是运用我们一开始实现的简单工厂模式
总结
简单工厂模式类型是创建型,但是它不属于23种设计模式,它只是一种实现方法。运用场景创建的对象比较少,然后工厂只需要知道需要什么就返回什么然后也不需要关心关键逻辑的时候就可以使用简单工厂模式,优点:客户端可以免除创建对象的责任直接交给工厂进行创建还有就是 只需要知道传入的参数就可以获取到所需要的参数而且无需知道创建细节。缺点就是违背了开闭原则还违反了高内聚低耦合的原则。
最后
开胃小菜已经奉上,下一篇来看工厂模式更高级的实现。欢迎关注转发,最后在附一个简单工厂模式的逻辑导图
参考资料
[1]
工厂模式介绍: 参考菜鸟教程
[2]
GOF: https://baike.baidu.com/item/GoF