开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
前言
如果你工作几年还经常通过New来实例化一个类,那么这篇可以来看看了,我们在写代码有一个很重要的原则就是解耦,通过解耦的方式让我们项目的代码更近简洁、清晰,不必一个地方改动很多地方都要进行修改,这篇来讲讲把类的实例化交给工厂来做,让我们代码的可扩展性较高。
工厂模式
何为工厂,顾名思义依靠某种介质生产我们所需要的东西,举个🌰正如有时候我们出去买东西,去普通商店买的东西就较贵,而去工厂店里面去买,则价格会相对优惠些,并且可买东西的种类也比较多,回过头我们看我们代码的设计模式。
Spring的工厂模式
关于工厂模式在Spring中体现比较常见的就是BeanFactory和FactoryBean,是Spring管理Bean的基础,这里有个对比的知识点,就是BeanFactory和FactoryBean的区别,了解Spring bean加载机制都知道,BeanFactory是IOC的核心,也是Spring的顶级接口;FactoryBean工厂是通过getObject方法来创建并返回对象,是一个针对Bean实现的定制化工厂,当然两者都离不开”工厂“两字。
传统模式
再结合我们的业务实现,举个业务场景,我们的订单系统在日常生成订单,然后通过结算系统进行付款结算的时候,通常对接的付款渠道不止一个,可能有多个,比如支付宝、微信支付、银行卡支付,这个时候我们去对这些渠道进行操作的时候,传统方式我们需要实现比如说3个接口,关于支付宝、微信、银行卡的接口,并且实现它们对应的业务方法,调取对应的第三方付款接口,最终将结果会写到数据库对应的表中。
单例、工厂模式设计
ChannelFactoryUtil
首先是创建工厂调用工具类,通过getFactory方法获取不同的渠道工厂。
方式一:
public class ChannelFactoryUtil {
/**
* 获取渠道工厂
*
* @param channelType
* @return
*/
public ChannelFactory getFactory(ChannelType channelType) {
ChannelFactory channelFactory = null;
switch (channelType) {
case WX_CHANNEL:
channelFactory = WxChannelFactory.getInstance();
break;
case PAYMENT_CHANNEL:
channelFactory = PaymentChannelFactory.getInstance();
break;
case BANK_CHANNEL:
channelFactory = BankChannelFactory.getInstance();
break;
default:
// 未配置,直接走默认的服务
channelFactory = CommonChannelFactory.getInstance();
break;
}
return channelFactory;
}
}
方式二:
如果这些渠道都需要进行发短息服务的对接,那么就可以通过,工厂的模式根据不同的channelType,获取到不同业务渠道对于发送短信的接口实现类。
public SendNoteService getService(ChannelType channelType) {
SendNoteService sendNoteService = null;
switch (channelType) {
case WX_CHANNEL:
sendNoteService = SpringContextUtils.getBean(WechatServiceImpl.class);
break;
case PAYMENT_CHANNEL:
// ...
break;
case BANK_CHANNEL:
// ...
break;
default:
break;
}
return sendNoteService;
}
SendNoteService 公共发短信方法
public interface SendNoteService{
void sendNoteMessage();
}
WechatServiceImpl
@Service
public class WechatServiceImpl implements WechatService,SendNoteService {
/**
* 微信支付方法
*/
@Override
public void wechatPayMethod() {
}
/**
* 发短信
*/
@Override
public void sendNoteMessage() {
//自定义实现微信的发短信方法
....
}
}
ChannelFactory
这里声明ChannelFactory接口,用来初始化不同的service,实现不同的业务接口,可以针对每个渠道的不同写不同的sevice,返回统一都是接口类型;包括实现公共接口,这里我在ChannelFactory接口里,写了一个公共的service么,以及不同业务所需要的服务接口。
public interface ChannelFactory {
//公共service
CommonService factoryUserMethod();
//可以去写不同针对不同业务的service
//微信服务service
WechatService getWechatServiceMethod();
//支付宝服务service
PaymentService getWechatServiceMethod();
//银行服务service
BankService getBankServiceMehtod();
}
WxChannelFactory
接下来就是实现不同业务渠道的工厂类,这里我只写一个,拿微信的业务渠道为例,实现ChannelFactory接口,获取对应的公共接口,并且通过单例模式进行初始化,这里使用的是懒汉模式+ duble check的加锁方式来实现的单例模式。
public class WxChannelFactory implements ChannelFactory {
private volatile static ChannelFactory channelFactory = null;
public WxChannelFactory() {
}
public static ChannelFactory getInstance() {
if (channelFactory == null) {
synchronized (WxChannelFactory.class) {
if (channelFactory == null) {
channelFactory = new WxChannelFactory();
}
}
}
return channelFactory;
}
@Override
public CommonService factoryUserMethod() {
return SpringContextUtils.getBean(UserServiceImpl.class);
}
@Override
public WechatService getWechatServiceMethod() {
return null;
}
}
执行Controller
@RestController
@Slf4j
public class TestController {
@Autowired
private ChannelFactoryUtil channelFactoryUtil;
@GetMapping("/testMethod")
public void testMethod(){
//获取微信渠道的service
ChannelFactory channelFactory = channelFactoryUtil.getFactory(ChannelType.WX_CHANNEL);
WechatService wechatService =channelFactory.getWechatServiceMethod();
//执行微信支付方法
wechatService.wechatPayMethod();
//获取微信发短信的方法
SendNoteService wechatNoteService =channelFactoryUtil.getService(ChannelType.WX_CHANNEL);
//执行发短信的方法
wechatNoteService.sendNoteMessage();
}
}
总结
通过上面工厂模式对我们的业务类进行加载,是不是更加清晰了呢,可扩展性强,耦合度较低,如果业务方法发生改变,只需要修改对应的底层业务方法,不需要对每个实现进行修改,通过设计模式让我们的代码结构清晰,同时能锻炼我们对项目构建的能力,何乐而不为呢。