策略模式 + 反射工厂 很好的实现了开闭原则

    xiaoxiao2025-07-23  7

    应用场景:某天接到了一个需求,品牌给了一个第三方接口,例如:www.baidu.com,我们通过调用这个第三接口,会返回4种状态,ex:

    String pageStatus = "pdpAdvertisePage";  代表我们经过一堆处理后要返回的是pdp广告页面

    String pageStatus = "plpAdvertisePage";   代表我们经过一堆业务处理后要返回的是plp广告页面

    String pageStatus = "shoppingCartAdvertisePage"; 代表我们经过一堆业务处理后要返回的是购物车广告页面

    String pageStatus = "checkoutAdvertisePage"; 代表我们经过一堆业务处理后要返回的是购物车广告页面

    期间的解决方案一:做了好多的判断 if elseif  elseif 写到后面我都不知道里面的判断逻辑是啥,太复杂了,果断放弃了

    期间的解决方案二:利用了策略模式+简单工厂模式,总算把那些个if else给去掉了,逻辑算是比较清晰了

    期间的解决方案三:利用策略模式+反射工厂,很完美的解决了简单工厂模式所带来的弊端 -- 实现了所谓的开闭原则

    代码目录结构:

    公共的接口: 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实现接口代码: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实现接口代码: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"; } }

    结算实现接口代码: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"; } }

    生产广告页面。简单工厂类 GetPointAdvertisePageReflectFactory.java,案例未使用,但代码贴出来了,供读者对比两个的差异,感受一下,开闭原则,对比一下,简单工厂和反射工厂的不同。

    思考角度,如果需求在加一个策略类,2个、3个? 那么你就感受到了

    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 : 生产广告页面简单工厂 * @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 ); } /** 根据pageType 得到指定的处理类 */ public GetPointAdvertisePageStrategey getStrategey(String pageType) { if(Validator.isNullOrEmpty(recommendStrategyMap)){ init(); } return recommendStrategyMap.get(pageType); } }

     

    生产广告页面。反射工厂类 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 : 生产广告页面反射工厂 * @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; //通过反射创建对象 Class<?> handler = Class.forName(classPath); //这里必须强行纳入spring管理,否则在得到的具体实现类中,如果有通过@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; /** * 获取配置文件参数工具类 * 拥有缓存功能,当查询了某个文件时会自动缓存 * @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

    # 下面是每个实现类的具体路径,利用反射的原理来达到获取某个具体类的目的 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("通过配置文件和反射机制,在运行时动态获取指定的执行类,测试成功"); LOGGER.info(getPointAdvertisePageStrategey.getAdvertisePage()); } } }

     

    最新回复(0)