一次代碼優(yōu)化實踐,用了模板方法+策略+工廠方法模式
前言
好久沒分享工作總結啦,今天來一份代碼優(yōu)化總結。用模板方法+策略+工廠方法模式優(yōu)化了代碼,耐心點看完,應該對大家有幫助的~
本文已經收錄到github
https://github.com/whx123/JavaHome
優(yōu)化代碼前
先來了解一下類似的業(yè)務場景,簡言之,就是:多個商戶接入我們系統(tǒng),都是走一個類似的流程通過http請求出去的。
優(yōu)化前,每個公司對應一個句柄服務,偽代碼如下:
- // 商戶A處理句柄
- CompanyAHandler implements RequestHandler {
- Resp hander(req){
- //查詢商戶信息
- queryMerchantInfo();
- //加簽
- signature();
- // http請求(走代理)
- httpRequestbyProxy()
- // 驗簽
- verify();
- }
- }
- // 商戶B處理句柄
- CompanyBHandler implements RequestHandler {
- Resp hander(Rreq){
- //查詢商戶信息
- queryMerchantInfo();
- //加簽
- signature();
- // http請求(不走代理)
- httpRequestbyDirect();
- // 驗簽
- verify();
- }
- }
- // 商戶C處理句柄
- CompanyBHandler implements RequestHandler {
- Resp hander(Rreq){
- //查詢商戶信息
- queryMerchantInfo();
- // webservice 方式調用
- requestByWebservice();
- }
- }
優(yōu)化代碼思路
我的優(yōu)化代碼思路,是有「重復代碼,先把它抽出來,或者公用變量,或者公用方法,伸著公用類」。所以呢,查詢商戶信息呀,加簽呀,http請求呀先全部各抽成一個公用方法。你細心點會發(fā)現(xiàn),連每個Handler處理過程都很類似的,大概都是查詢商戶信息+加簽+http請求+驗簽,于是呢,可以直接把它們抽象成一個公用類呀~在這里就要引入模板方法模式咯
模板方法模式
- 在模板模式(Template Pattern)中,一個抽象類公開定義了執(zhí)行它的方法的方式/模板。它的子類可以按需要重寫方法實現(xiàn),但調用將以抽象類中定義的方式進行。
- 這種類型的設計模式屬于行為型模式。
這種類型的設計模式屬于行為型模式。
既然每個Handler處理,都是類似的流程,那「定義一個抽象類,把查詢商戶信息,加簽,http請求,驗簽什么的,都放到里面去,儼然一個模板一樣」。然后,因為有些商戶走http代理,有些又沒走代理,怎么辦呢? 定義「一個抽象方法,給子類實現(xiàn)」嘛,因為能共用就放到父類(當前的抽象類),不能共用就放到子類嘛~代碼如下:
- abstract class AbstractCompanyCommonService implements ICompanyCommonService {
- //模板方法
- Resp handlerTempPlate(req){
- //查詢商戶信息
- queryMerchantInfo();
- // 加簽
- signature();
- //http 請求
- if(isRequestByProxy()){
- httpProxy();
- }else{
- httpDirect();
- }
- // 驗簽
- verifySinature();
- }
- // Http是否走代理
- abstract boolean isRequestByProxy();
- }
子類商戶A實現(xiàn):
- CompanyAServiceImpl extends AbstractCompanyCommonService{
- Resp hander(req){
- return handlerTempPlate(req);
- }
- //公司A是走代理的
- boolean isRequestByProxy(){
- return true;
- }
子類商戶B實現(xiàn):
- CompanyBServiceImpl extends AbstractCompanyCommonService{
- Resp hander(req){
- return handlerTempPlate(req);
- }
- //公司B是不走代理的
- boolean isRequestByProxy(){
- return false;
- }
策略模式
心細的讀者會發(fā)現(xiàn),甚至提出疑問,「你的商戶C的服務實現(xiàn)跟你定義的公用模板,不太一樣呢」,那當然,實際開發(fā)中,不跟你定義的模板一樣太常見了,需求是產品提的嘛,又不是根據(jù)你模板提的,是代碼服務于需求的。好了,不多說啦,我使用了策略模式,來優(yōu)化這個問題。
- 在策略模式(Strategy Pattern)中,一個類的行為或其算法可以在運行時更改。這種類型的設計模式屬于行為型模式。
策略模式理解起來其好抽象對不對?我個人理解,其實策略模式就是定義一個方法(所謂算法),給子類自己去實現(xiàn)。實際上就是「定義個方法/接口,讓子類自己去實現(xiàn)」。看代碼吧:
- // 定義一個方法,把策略交給子類去實現(xiàn)。
- interface ICompanyCommonService{
- Resp hander(req);
- }
前面商戶A和商戶B還是不變,使用抽象類AbstractCompanyCommonService的模板,模板不滿足商戶C,商戶C只能自己去實現(xiàn)咯,各個子類自己去實現(xiàn)的行為,就是策略模式的體現(xiàn)呢,如下:
- CompanyCServiceImpl extends AbstractCompanyCommonService{
- Res hander(req){
- //查詢商戶信息
- queryMerchantInfo();
- requestByWebservice();
- }
- //隨意了,你都不走模板了
- boolean isRequestByProxy(){
- return false;
- }
工廠方法模式
商戶A、B、C服務怎么被管理呢,之前分別給A,B,C服務實現(xiàn)handler的,現(xiàn)在好了,都不知道怎么管理了,怎么知道調用哪個呢?別慌,解決方案是「工廠方法模式」。
- 在工廠模式中,我們在創(chuàng)建對象時不會對客戶端暴露創(chuàng)建邏輯,并且是通過使用一個共同的接口來指向新創(chuàng)建的對象。
工廠方法模式具體實現(xiàn)就是:接口定義一個枚舉,每個服務實現(xiàn)都重新實現(xiàn)枚舉,設置唯一標志枚舉,再交給spring容器管理??创a咯:
- interface ICompanyCommonService{
- Resp hander(req);
- CompanyEnum getCompanyEnum();
- }
- CompanyAServiceImpl extends AbstractCompanyCommonService{
- Resp hander(req){
- return handlerTempPlate(req);
- }
- //公司A是走代理的
- boolean isRequestByProxy(){
- return true;
- }
- CompanyEnum getCompanyEnum(){
- return CompanyEnum.A;
- }
- CompanyBServiceImpl extends AbstractCompanyCommonService{
- Resp hander(req){
- return handlerTempPlate(req);
- }
- //公司B是不走代理的
- boolean isRequestByProxy(){
- return false;
- }
- CompanyEnum getCompanyEnum(){
- return CompanyEnum.B;
- }
來來來,工廠方法模式出爐咯:
- @Component
- public class CompanyServiceFactory implements ApplicationContextAware {
- private static Map<CompanyEnum, ICompanyCommonService> map = new HashMap<>();
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- Map<String, ICompanyCommonService> tempMap = applicationContext.getBeansOfType(ICompanyCommonService.class);
- tempMap.values().forEach(iCompanyCommonService ->
- map.put(iCompanyCommonService.getCompanyEnum(), iCompanyCommonService));
- }
- public Resp handler(req) {
- return map.get(CompanyEnum.getCompanyEnum(req.getCompanyFlag()).hander(req);
- }
- }
最后建議
最后,不要為了使用設計模式生搬硬套,而是優(yōu)化代碼過程中,發(fā)現(xiàn)這個設計模式剛好適用,才去用的哈。附上最后的代碼咯:
- @Service
- public class CompanyHandler implements RequestHandler {
- @Autowire
- private CompanyServiceFactory companyServiceFactory;
- Resp hander(req){
- return companyServiceFactory.handler(req);
- }
- }
本文轉載自微信公眾號「撿田螺的小男孩」,可以通過以下二維碼關注。轉載本文請聯(lián)系撿田螺的小男孩公眾號。