Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

工厂模式介绍

工厂模式也称简单工厂模式,是创建型设计模式的一种,这种设计模式提供了按需创建对象的最佳方式。同时,这种创建方式不会对外暴露创建西街,并且会通一个统一的接口创建所需对象。

这种设计模式也是Java开发中常见的一种模式,它的主要意图是定义一个创建对象的接口,让其子类自己决定将哪个工厂类实例化,工厂模式使创建过程延迟到子类中进行。

简单的说,就是为了给代码结构提供扩展性,屏蔽每一个功能类中的具体实现逻辑。这种方式便于外部更简单地调用,同时也是去掉众多if···else的最佳手段。当然,这种设计模式也有一些缺点,需要治理。例如实现的类比较多、难以维护、开发成本高等,但这些问题都可以通过结合不同的设计模式逐步解决。

工厂模式的简单使用

在这里就举例一种在业务中常见的一种情况,if else大法,每次我看到代码一堆的if else我就感到头痛,虽然if else 用起来确实十分的香,而且实现业务需求十分的快速便捷,但是当维护起来简直就是噩梦。万一自己写的if else 大法交给别人来维护,我怕有人对我施展C语言。

需求:模拟发放多个产品,这里根据不同的类型兑换不同的奖励,类型当然有多种多样,比如优惠券、实体商品、第三方的兑换卡(爱奇艺会员、腾讯会员等等)。

违背设计模式实现

来我们先看最简单实现方式(不得不说在业务中,我经常这样写)

1、我们先定义一个入参类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package bestrookie.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author bestrookie
* @date 2021/10/27 3:02 下午
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AwardReq {
private Integer id;
private String userName;
private Integer type;
}

2、然后我们根据奖励的类型写不同的兑换奖品的逻辑(具体的业务逻辑就不实现了)

优惠券:

1
2
3
4
5
6
7
8
9
10
11
package bestrookie.service;
import bestrookie.pojo.AwardReq;
/**
* @author bestrookie
* @date 2021/10/27 3:07 下午
*/
public class CouponService {
public void send(AwardReq awardReq){
System.out.println("发放优惠券====》"+awardReq.getUserName());
}
}

实体商品:

1
2
3
4
5
6
7
8
9
10
11
package bestrookie.service;
import bestrookie.pojo.AwardReq;
/**
* @author bestrookie
* @date 2021/10/27 3:09 下午
*/
public class GoodService {
public void send(AwardReq awardReq){
System.out.println("发送实体商品===》"+awardReq.getUserName());
}
}

三方兑换卡:

1
2
3
4
5
6
7
8
9
10
11
package bestrookie.service;
import bestrookie.pojo.AwardReq;
/**
* @author bestrookie
* @date 2021/10/27 3:11 下午
*/
public class QiYiUserService {
public void send(AwardReq awardReq){
System.out.println("爱奇艺兑换码====》"+awardReq.getUserName());
}
}

3、然后就是根据类型调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package bestrookie.controller;
import bestrookie.pojo.AwardReq;
import bestrookie.service.CouponService;
import bestrookie.service.GoodService;
import bestrookie.service.QiYiUserService;
/**
* @author bestrookie
* @date 2021/10/27 3:13 下午
*/
public class PrizeController {
public static void main(String[] args) {
AwardReq awardReq = new AwardReq(1,"bestrookie",1);
if (awardReq.getType() == 1){
CouponService couponService = new CouponService();
couponService.send(awardReq);
}else if (awardReq.getType() == 2){
GoodService goodService = new GoodService();
goodService.send(awardReq);
}else if (awardReq.getType() == 3){
QiYiUserService qiYiUserService = new QiYiUserService();
qiYiUserService.send(awardReq);
}
System.out.println("========发放完成=========");
}
}

这个if else 是不是十分的经典,这样代码虽然看起来并不是很多,但是这也是我们各种业务的逻辑都省略了,所以看起来代码少,在真实业务中中间还有很多业务处理。

工厂模式重构代码

设想的结构

image-20211027170123512

1、首先定义公共方法的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
package bestrookie.interfaces;
import bestrookie.pojo.AwardReq;
/**
* @author bestrookie
* @date 2021/10/27 3:26 下午
*/
public interface ICommodity {
/**
* 兑换奖品
* @param awardReq 参数
*/
void send(AwardReq awardReq);
}

2、定义各种奖励的实现类

优惠券:

1
2
3
4
5
6
7
8
9
10
11
12
package bestrookie.service;
import bestrookie.interfaces.ICommodity;
import bestrookie.pojo.AwardReq;
/**
* @author bestrookie
* @date 2021/10/27 3:32 下午
*/
public class CouponCommodityService implements ICommodity {
public void send(AwardReq awardReq) {
System.out.println("获得优惠券=====>"+awardReq.getUserName());
}
}

实体商品:

1
2
3
4
5
6
7
8
9
10
11
12
package bestrookie.service;
import bestrookie.interfaces.ICommodity;
import bestrookie.pojo.AwardReq;
/**
* @author bestrookie
* @date 2021/10/27 3:34 下午
*/
public class GoodCommodityService implements ICommodity {
public void send(AwardReq awardReq) {
System.out.println("获得实物商品====》"+awardReq.getUserName());
}
}

三方兑换卡:

1
2
3
4
5
6
7
8
9
10
11
12
package bestrookie.service;
import bestrookie.interfaces.ICommodity;
import bestrookie.pojo.AwardReq;
/**
* @author bestrookie
* @date 2021/10/27 3:31 下午
*/
public class CardCommodityService implements ICommodity {
public void send(AwardReq awardReq) {
System.out.println("三方兑换卡片=====》"+awardReq.getType());
}
}

3、创建工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package bestrookie.factory;
import bestrookie.interfaces.ICommodity;
import bestrookie.pojo.AwardReq;
import bestrookie.service.CardCommodityService;
import bestrookie.service.CouponCommodityService;
import bestrookie.service.GoodCommodityService;
/**
* @author bestrookie
* @date 2021/10/27 3:35 下午
*/
public class StoreFactory {
public ICommodity getCommodityService(AwardReq awardReq) {
if (awardReq.getType() == 1){
return new CouponCommodityService();
}
if (awardReq.getType() == 2){
return new GoodCommodityService();
}
if (awardReq.getType() == 3){
return new CardCommodityService();
}
throw new RuntimeException("不存在服务类型");
}
public ICommodity getCommodityService(Class<?extends ICommodity> clazz) throws InstantiationException, IllegalAccessException {
if (clazz ==null){
return null;
}
return clazz.newInstance();
}
}

4、实际调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package bestrookie.controller;
import bestrookie.factory.StoreFactory;
import bestrookie.interfaces.ICommodity;
import bestrookie.pojo.AwardReq;
/**
* @author bestrookie
* @date 2021/10/27 3:43 下午
*/
public class StoreFactoryController {
public static void main(String[] args) {
AwardReq awardReq = new AwardReq(1,"bestrookie",2);
StoreFactory storeFactory = new StoreFactory();
ICommodity commodityService = storeFactory.getCommodityService(awardReq);
commodityService.send(awardReq) ;
}
}
  • 从上面代码中可以看到,每一种奖品都包装到自己的类中,当新增、修改或删除逻辑时,都不会影响到其他奖品功能的测试,可以降低回归测试和响应的连带风险
  • 如果有新增的奖品,只需要按照此结构进行填充对应的实现类即可。这样的实现方式非常易于维护和扩展
  • 我们还可以统一入参以及出参,调用方不再关心奖品发放的内部逻辑,按照统一的方式即可处理

总结

从优化的过程来看,工厂模式并不复杂。一旦理解和掌握,会发现它更加简单,同时也可以借助它提升开发效率。同时,不难总结出它的有点:避免创建者与具体的产品逻辑耦合;满足单一职责,每一个业务逻辑实现都在自己所属的类中完成;满足开闭原则,无须更改使用调用方就可以在程序中引入新的产品类型。当然,这也将会带来一些问题,例如如有十分多的奖品类型,那么子类会急速扩张,因此需要使用其他的模式进行优化。

评论