基本上,大家都能说上两句设计模式的事,其他不说,单例模式总该知道吧。设计模式是由多年的经验提炼出来开发指导思想。今天开启设计模式系列的学习:
创建型模式之工厂模式:
概念:工厂模式又称工厂方法模式,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。即对象创建过程延迟到子类实现。
提供了代码的扩展性,屏蔽了每一个功能类中的具体实现逻辑。外部只需调用即可,可以去掉众多的 if-else 。
案例
购买商品(会员),比如 饿了吗/美团/饿了吗+网易云组合。
直接实现功能
首先是满足需求的,而且按时完成了任务,还完成的很快。
但是如果,我现在需要新增需求,加一个:美团+网易云组合。那得改主要逻辑类,而且都得回归测试,因为你懂了主要得逻辑类。所以,以前写的都必须重新测试。显然不合理。
import com.alibaba.fastjson.JSON;
import com.practic.thinkinpatterndesign.工厂模式.CommonReq;
import com.practic.thinkinpatterndesign.工厂模式.CommonRes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CommonController {
private Logger logger = LoggerFactory.getLogger(CommonController.class);
public CommonRes CommonBuy(CommonReq req) {
String reqJson = JSON.toJSONString(req);
try {
logger.info("客户购买开始:{},req:{}",req.getBuyBusiId(),reqJson);
//按照不同的类型组合商品//1.饿了吗;2.美团;3.饿了吗+网易云
if(req.getBuyType()==1){
//对接饿了吗系统
System.out.println("单独购买饿了吗:成功");
return CommonRes.ok("单独购买饿了吗成功:"+req.getBuyBusiId());
}else if(req.getBuyType()==2){
//对接美团系统
System.out.println("单独购买美团:成功");
return CommonRes.ok("单独购买美团成功:"+req.getBuyBusiId());
}else if(req.getBuyType()==3){
//对接饿了吗系统+网易云
System.out.println("组合购买饿了吗+网易云:成功");
return CommonRes.ok("组合购买饿了吗+网易云成功:"+req.getBuyBusiId());
}
} catch (Exception e) {
logger.error("购买失败:{},req:{}",req.getBuyBusiId(),reqJson);
return CommonRes.error();
}
return CommonRes.ok("成功");
}
import lombok.Data;
@Data
public class CommonReq {
private String buyBusiId; //订单流水号
private int buyType; //订单关联的商品类型
private int userId; //用户唯一id
}
import lombok.Data;
import java.util.HashMap;
import java.util.Objects;
@Data
public class CommonRes extends HashMap<String, Object> {
private int code;
private String msg;
private Object data;
private static final String MSG_SUCCESS = "成功";
private static final int CODE_SUCCESS = 0;
private static final String MSG_FAIL = "失败";
private static final int CODE_FAIL = 1;
public CommonRes(int code, String msg) {
super.put("code", code);
super.put("msg", msg);
}
public CommonRes(int code, String msg, Object data) {
super.put("code", code);
super.put("msg", msg);
if (!Objects.isNull(data)) {
super.put("data", data);
}
}
/**
* 成功返回示例
*/
public static CommonRes ok() {
return new CommonRes(CODE_SUCCESS, MSG_SUCCESS,null);
}
public static CommonRes ok(String msg) {
return new CommonRes(CODE_SUCCESS, msg,null);
}
public static CommonRes ok(Object data) {
return new CommonRes(CODE_SUCCESS, MSG_SUCCESS, data);
}
public static CommonRes ok(String msg, Object data) {
return new CommonRes(CODE_SUCCESS, msg, data);
}
/**
* 失败返回示例
*/
public static CommonRes error() {
return new CommonRes(CODE_FAIL, MSG_FAIL,null);
}
public static CommonRes error(String msg) {
return new CommonRes(CODE_FAIL, msg,null);
}
public static CommonRes error(String msg, Object data) {
return new CommonRes(CODE_FAIL, msg, data);
}
}
@Test
public void test_buy(){
CommonController commonController=new CommonController();
System.out.println("模拟购买商品====");
//业务类型为 1
CommonReq req1=new CommonReq();
req1.setBuyType(1);
req1.setBuyBusiId("20221112093689123423");
req1.setUserId(67855);
CommonRes res1=commonController.CommonBuy(req1);
logger.info("请求参数:{}", JSON.toJSONString(req1));
logger.info("测试结果:{}",JSON.toJSONString(res1));
//业务类型为 2
CommonReq req2=new CommonReq();
req2.setBuyType(2);
req2.setBuyBusiId("20221112093689123423");
req2.setUserId(67855);
CommonRes res2=commonController.CommonBuy(req2);
logger.info("请求参数:{}", JSON.toJSONString(req2));
logger.info("测试结果:{}",JSON.toJSONString(res2));
}
工厂方法
一个购买接口
public interface BuyService {
public CommonRes buyCommon(CommonReq req);
}
各种具体的实现:这里是三个实现
public class MTbuyServiceImpl implements BuyService {
private Logger logger = LoggerFactory.getLogger(MTbuyServiceImpl.class);
@Override
public CommonRes buyCommon(CommonReq req) {
logger.info("美团入参:{}", JSON.toJSONString(req));
//1.获取用户,生成流水号,拼接入参
//2.调用美团系统,处理逻辑
//3.返回
return CommonRes.ok("美团购买成功");
}
}
public class ELMbuyServiceImpl implements BuyService {
private Logger logger = LoggerFactory.getLogger(ELMbuyServiceImpl.class);
@Override
public CommonRes buyCommon(CommonReq req) {
logger.info("饿了吗入参:{}", JSON.toJSONString(req));
//1.获取用户,生成流水号,拼接入参
//2.调用饿了吗系统,处理逻辑
//3.返回
return CommonRes.ok("饿了吗购买成功");
}
}
public class ELMandWYYbuyServiceImpl implements BuyService {
private Logger logger = LoggerFactory.getLogger(ELMandWYYbuyServiceImpl.class);
@Override
public CommonRes buyCommon(CommonReq req) {
logger.info("饿了吗+网易云入参:{}", JSON.toJSONString(req));
//1.获取用户,生成流水号,拼接入参
//2.调用饿了吗+网易云系统,处理逻辑
//3.返回
return CommonRes.ok("饿了吗+网易云购买成功");
}
}
工厂类:统一处理
public class StoreFactory {
public BuyService getBuy(int buyType) {
if (buyType == 1) {
return new ELMbuyServiceImpl();
}
if (buyType == 2) {
return new MTbuyServiceImpl();
}
if (buyType == 3) {
return new ELMandWYYbuyServiceImpl();
}
throw new RuntimeException("不存在商品类型");
}
}
测试类:
@Test
public void test_buy(){
//懒得写入参了,就这一个吧 0.0
CommonReq req1=new CommonReq();
req1.setBuyType(1);
req1.setBuyBusiId("20221112093689123423");
req1.setUserId(67855);
StoreFactory factory = new StoreFactory();
BuyService buyService1 = factory.getBuy(1);
CommonRes res1 = buyService1.buyCommon(req1);
logger.info("购买饿了吗成功:{}", JSON.toJSONString(res1));
BuyService buyService2 = factory.getBuy(2);
CommonRes res2 = buyService2.buyCommon(req1);
logger.info("购买美团成功:{}",JSON.toJSONString(res2));
BuyService buyService3 = factory.getBuy(3);
CommonRes res3 = buyService3.buyCommon(req1);
logger.info("购买饿了吗+网易云成功:{}",JSON.toJSONString(res3));
}
我们将具体实现推迟到子类实现,这里很方便的是:如果新增需求,只需要写一个实现购买方法的接口即可。
而且不用回归测试其他原来已经写好的需求,因为都没有动。
思考:这里的工厂类,其实还是一个 if-else。但是可以将工厂类也做成一个接口,然后推迟到子类实现。
这样的做法就是避免了高耦合,但是类膨胀了(增加了额外的子类实现)
总结
| 不使用工厂 | 工厂模式 | |
|---|---|---|
| 优 | 开发快,开发逻辑清晰明了,一个类解决问题 | 低耦合,利于扩展,结构也清晰明了 |
| 缺 | 高度耦合,不利于拓展 | 类膨胀 |