一種思路:策略模式 + 反射工廠,很好的實現(xiàn)了開閉原則

作者 | 麻辣你個王子
應用場景:某天接到了一個需求,品牌給了一個第三方接口,例如:www.baidu.com,我們通過調用這個第三接口,會返回4種狀態(tài),ex:
String pageStatus = "pdpAdvertisePage";代表我們經(jīng)過一堆處理后要返回的是pdp廣告頁面String pageStatus = "plpAdvertisePage";代表我們經(jīng)過一堆業(yè)務處理后要返回的是plp廣告頁面String pageStatus = "shoppingCartAdvertisePage";代表我們經(jīng)過一堆業(yè)務處理后要返回的是購物車廣告頁面String pageStatus = "checkoutAdvertisePage";代表我們經(jīng)過一堆業(yè)務處理后要返回的是購物車廣告頁面
期間的解決方案一: 做了好多的判斷 if elseif elseif 寫到后面我都不知道里面的判斷邏輯是啥,太復雜了,果斷放棄了
期間的解決方案二: 利用了策略模式+簡單工廠模式,總算把那些個if else給去掉了,邏輯算是比較清晰了
期間的解決方案三: 利用策略模式+反射工廠,很完美的解決了簡單工廠模式所帶來的弊端 -- 實現(xiàn)了所謂的開閉原則
代碼目錄結構:
公共的接口:GetPointAdvertisePageStrategey.java
import org.springframework.ui.Model;
/**
* @author : David.liu
* @description : 得到指定廣告頁面
* @creat :2019-05-26-22:02
*/
public interface GetPointAdvertisePageStrategey {
/**
* 得到指定的頁面
* @param itemRecommendParam
* @param model
* @return
*/
String getAdvertisePage(Model model);
}
Ppd實現(xiàn)接口代碼:PdpAdvertisePageStrategey.java
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
/**
* @author : David.liu
* @description : 得到pdp廣告頁面
* @creat :2019-05-26-22:05
*/
@Component
public class PdpAdvertisePageStrategey implements GetPointAdvertisePageStrategey{
/**
* 得到指定的頁面
*
* @param itemRecommendParam
* @param model
* @return
*/
@Override
public String getAdvertisePage() {
return "pdp-advertise.jsp";
}
}
Plp實現(xiàn)接口代碼:PlpAdvertisePageStrategey.java
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
/**
* @author : David.liu
* @description : 得到指定的plp廣告頁面
* @creat :2019-05-26-22:07
*/
@Component
public class PlpAdvertisePageStrategey implements GetPointAdvertisePageStrategey {
/**
* 得到指定的plp廣告頁面
*
* @param itemRecommendParam
* @param model
* @return
*/
@Override
public String getAdvertisePage() {
return "plp-advertise.jsp";
}
}
ShopingCartAdvertisePageStrategey.java
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
/**
* @author : David.liu
* @description : 得到購物車廣告頁面
* @creat :2019-05-26-22:10
*/
@Component
public class ShopingCartAdvertisePageStrategey implements GetPointAdvertisePageStrategey {
/**
* 得到指定的購物車頁面
*
* @param model
* @return
*/
@Override
public String getAdvertisePage() {
return "shoppingcart-advertise.jsp";
}
}
結算實現(xiàn)接口代碼:CheckoutAdvertisePageStrategey.java
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
/**
* @author : David.liu
* @description : 得到結算頁面廣告頁面
* @creat :2019-05-26-22:12
*/
@Component
public class CheckoutAdvertisePageStrategey implements GetPointAdvertisePageStrategey {
/**
* 得到指定的結算頁面
*
* @param itemRecommendParam
* @param model
* @return
*/
@Override
public String getAdvertisePage() {
return "checkout-advertise.jsp";
}
}
生產(chǎn)廣告頁面。簡單工廠類 GetPointAdvertisePageReflectFactory.java,案例未使用,但代碼貼出來了,供讀者對比兩個的差異,感受一下,開閉原則,對比一下,簡單工廠和反射工廠的不同。
如果您正在學習Spring Boot,推薦一個連載多年還在繼續(xù)更新的免費教程:http://blog.didispace.com/spring-boot-learning-2x/
import com.feilong.core.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author : David.liu
* @description : 生產(chǎn)廣告頁面簡單工廠
* @creat :2019-05-26-22:14
*/
@Component
public class GetPointAdvertisePageSimpleFactory {
public static final String PDP_ITEM_ADVERTISE = "PDP_ITEM_ADVERTISE";
public static final String PLP_ITEM_ADVERTISE = "PLP_ITEM_ADVERTISE";
public static final String CHECKOUT_ITEM_ADVERTISE = "CHECKOUT_ITEM_ADVERTISE";
public static final String SHOPPINGCART_ITEM_ADVERTISE = "SHOPPINGCART_ITEM_ADVERTISE";
private static Map<String, GetPointAdvertisePageStrategey> recommendStrategyMap = new HashMap<>();
@Autowired
private CheckoutAdvertisePageStrategey checkoutAdvertisePageStrategey;
@Autowired
private PdpAdvertisePageStrategey pdpAdvertisePageStrategey;
@Autowired
private PlpAdvertisePageStrategey plpAdvertisePageStrategey;
@Autowired
private ShopingCartAdvertisePageStrategey shopingCartAdvertisePageStrategey;
/** 初始化所有的策略類 */
protected void init(){
recommendStrategyMap.put(PDP_ITEM_ADVERTISE, pdpAdvertisePageStrategey);
recommendStrategyMap.put(PLP_ITEM_ADVERTISE,plpAdvertisePageStrategey );
recommendStrategyMap.put(CHECKOUT_ITEM_ADVERTISE, checkoutAdvertisePageStrategey);
recommendStrategyMap.put(SHOPPINGCART_ITEM_ADVERTISE,shopingCartAdvertisePageStrategey );
}
/** 根據(jù)pageType 得到指定的處理類 */
public GetPointAdvertisePageStrategey getStrategey(String pageType) {
if(Validator.isNullOrEmpty(recommendStrategyMap)){
init();
}
return recommendStrategyMap.get(pageType);
}
}
生產(chǎn)廣告頁面。反射工廠類 GetPointAdvertisePageReflectFactory.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
/**
* @author : David.liu
* @description : 生產(chǎn)廣告頁面反射工廠
* @creat :2019-05-26-22:15
*/
@Component
public class GetPointAdvertisePageReflectFactory {
@Autowired
private ApplicationContext context;
private static final Logger LOGGER = LoggerFactory.getLogger(GetPointAdvertisePageReflectFactory.class);
// 通過配置文件名:filePathName 和 文件中的key 得到指定的類
public GetPointAdvertisePageStrategey getAdvertisePageStrategey(String filePathName, String key){
GetPointAdvertisePageStrategey getPointAdvertisePageStrategey = null;
String classPath = null;
try {
classPath = PropertyUtil.get(filePathName,key);
if(Validator.isNullOrEmpty(classPath)) return null;
//通過反射創(chuàng)建對象
Class<?> handler = Class.forName(classPath);
//這里必須強行納入spring管理,否則在得到的具體實現(xiàn)類中,如果有通過@Autowired注入的bean,將會報注入失敗
getPointAdvertisePageStrategey = (GetPointAdvertisePageStrategey) context.getAutowireCapableBeanFactory().createBean(handler, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
} catch (Exception e) {
LOGGER.error("Failed to reflect the corresponding object through the specified path,filePath:{},key:{}",filePathName,key);
return null;
}
return getPointAdvertisePageStrategey;
}
}
文件讀取工具類: PropertyUtil.java
import com.feilong.core.Validator;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* 獲取配置文件參數(shù)工具類
* 擁有緩存功能,當查詢了某個文件時會自動緩存
* @author wei.liu5
* @Date 2019/5/20
*/
public class PropertyUtil {
private static Map<String, Properties> cache = new HashMap<>();
/**
*
* @param configFileName 配置文件名
* @param key 配置文件中的 key=value 中的key
* @return
*/
public static String get(String configFileName,String key){
return getProperties(configFileName).getProperty(key);
}
public static Properties getProperties(String configFileName) {
if (Validator.isNotNullOrEmpty(cache.get(configFileName))) {
return cache.get(configFileName);
}
InputStream inputStream = PropertyUtil.class.getResourceAsStream(configFileName);
Properties properties = new Properties();
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
cache.put(configFileName,properties);
return properties;
}
}
配置文件:itemrecommend.properties
# 下面是每個實現(xiàn)類的具體路徑,利用反射的原理來達到獲取某個具體類的目的
pdp.item.advertise=com.wy.store.web.manager.PdpAdvertisePageStrategey
plp.item.advertise=com.wy.store.web.manager.PlpAdvertisePageStrategey
shoppingcart.item.advertise=com.wy.store.web.manager.ShopingCartAdvertisePageStrategey
checkout.item.advertise=com.wy.store.web.manager.CheckoutAdvertisePageStrategey
測試類:測試代碼用的是 策略模式+反射工廠,這里未使用簡單工廠,但代碼也貼出來了
import com.feilong.core.Validator;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
public class ItemRecommendReflectFactoryTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ItemRecommendReflectFactoryTest.class);
@Autowired
private GetPointAdvertisePageReflectFactory getItemRecommendStrategey;
@Test
public void refectFactoryTest(){
String path = "/itemrecommend.properties";
GetPointAdvertisePageStrategey getPointAdvertisePageStrategey = getItemRecommendStrategey.getAdvertisePageStrategey(path,"pdp.item.advertise");
if(Validator.isNotNullOrEmpty(getPointAdvertisePageStrategey)){
LOGGER.info("通過配置文件和反射機制,在運行時動態(tài)獲取指定的執(zhí)行類,測試成功");
LOGGER.info(getPointAdvertisePageStrategey.getAdvertisePage());
}
}
}
- END -
往期推薦
關注我回復「加群」,加入Spring技術交流群


