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

应用场景:某天接到了一个需求,品牌给了一个第三方接口,例如: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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值