在寫業(yè)務(wù)代碼的時(shí)候我有時(shí)想寫一些策略模式工廠模式類似的代碼拆分業(yè)務(wù),可是在spring下有一些局限性.我們已經(jīng)使用了spring來(lái)管理對(duì)象的初始化,我們就沒(méi)法寫一些類似于
map.put("key",new object())
的代碼.其次同一接口下多個(gè)實(shí)現(xiàn)類需要使用
@Qualifier("a")
@Qualifier("b")
來(lái)區(qū)分,那么最終我們的代碼大概會(huì)寫成這個(gè)樣子
public class WxEventHandleFactory {
@Autowired
@Qualifier("scan")
private WxEventHandle scanHandle;
@Autowired
@Qualifier("subscribe")
private WxEventHandle subscribeHandle;
@Autowired
@Qualifier("unsubscribe")
private WxEventHandle unsubscribeHandle;
public WxEventHandle getHandle(String event) {
if (WxEventType.SUBSCRIBE.getCode().equals(event)) {
return subscribeHandle;
} else if (WxEventType.UNSUBSCRIBE.getCode().equals(event)) {
return unsubscribeHandle;
} else if (WxEventType.SCAN.getCode().equals(event)) {
return scanHandle;
}
return null;
}
}
這段代碼就是根據(jù)微信公眾號(hào)不同的消息,拆分了不同處理代碼.不好的點(diǎn)就是我們的策略方法會(huì)不斷的膨脹的,但這也不是不能接受,我在flink的某個(gè)連接redis做狀態(tài)存儲(chǔ)的開源項(xiàng)目下也看到過(guò)更大的類似方法,不過(guò)是用switch 拆分罷了.
那么我們有沒(méi)有更好的辦法呢?
我們可不可以通過(guò)一些類似標(biāo)記的方式給我們業(yè)務(wù)類打上獨(dú)有的標(biāo)記?
注解是一個(gè)不錯(cuò)的方案
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CallBack {
TypeEnum[] value();
}
這里value為什么是一個(gè)數(shù)組呢,因?yàn)槲蚁M鄠€(gè)策略使用同一個(gè)類處理.
我們?cè)趺磸膕pring的管理中獲取這些被我們標(biāo)記的類呢?
bean實(shí)例化后會(huì)注入ApplicationContext
@Component
public class MyBean {
@Autowired
private ApplicationContext context;
}
接下來(lái)我們只需要將標(biāo)有@CallBack的類統(tǒng)一使用數(shù)據(jù)結(jié)構(gòu)保存起來(lái),每次根據(jù)不同TypeEnum獲取即可,其次為了方便調(diào)用,我們所有的業(yè)務(wù)類肯定需要實(shí)現(xiàn)相同的方法
public interface BaseStrategyCallBack {
void doMethod(MyContext myContext);
}
@PostConstruct(bean初始化前執(zhí)行,相當(dāng)于init)
@Component
public class FactoryStrategy {
private static Map<TypeEnum, BaseStrategyCallBack> map = new ConcurrentHashMap<>();
@Autowired
private ApplicationContext context;
public static BaseStrategyCallBack createDoMethod(TypeEnum typeEnum) {
return map.get(doTypeEnum);
}
@PostConstruct
public void init() {
Map<String, Object> beansMap = context.getBeansWithAnnotation(CallBack.class);
beansMap.values()
.forEach(i -> {
OrderCallBack doTypeAnnotation = i.getClass().getAnnotation(CallBack.class);
for(ItemTypeEnum e : doTypeAnnotation.value()){
map.put(e, (BaseStrategyCallBack) i);
}
});
}
}
編寫業(yè)務(wù)類
@Log4j2
@Service
@CallBack(TypeEnum.test)
public class StrategyTest implements BaseStrategyCallBack {
@Override
public void doMethod(MyContext myContext) {
//業(yè)務(wù)邏輯
}
}
調(diào)用
FactoryStrategy.createDoMethod(typeEnum).doMethod(myContext);
至此我們就實(shí)現(xiàn)了基于spring的代碼拆分,根據(jù)不同的枚舉獲取不同的業(yè)務(wù)類.
ps:我平時(shí)是不看spring相關(guān)書籍去學(xué)習(xí)的,當(dāng)工作中需要的時(shí)候可能會(huì)點(diǎn)進(jìn)去看一丟丟源碼也是屬于看過(guò)就忘.但是有一點(diǎn)就是一定要去看官方文檔,畢竟spring的文檔算是開源項(xiàng)目里最完善的一批了.理解了ioc,aop.你就有了思考的脈絡(luò),剩下東西,我愿意稱為機(jī)制而不是技術(shù),所以機(jī)制的東西,在不會(huì)的時(shí)候去看文檔查一查就好.況且現(xiàn)在還有chatgpt,查文檔更是一絕.其次我也很少看設(shè)計(jì)模式相關(guān)的東西,因?yàn)橹灰阈闹杏蓄?接口,抽象類的概念,那你就可以梳理代碼的結(jié)構(gòu),以不變應(yīng)萬(wàn)變我覺(jué)得才是更好的方式.當(dāng)然這是我個(gè)人極端的想法,設(shè)計(jì)模式還是需要看的,只是我目前還沒(méi)有多余的時(shí)間,之前一直都是寫一些底層原理的文章,是因?yàn)槲覀€(gè)人比較癡迷這些東西.最近嘗試寫一些比較業(yè)務(wù)的東西,展示一下工作中的一些思路.