⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/qq_28675967/article/details/90581208 「麻辣你个王子」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

应用场景:某天接到了一个需求,品牌给了一个第三方接口,例如: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());
}
}
}

文章目录