策略模式
背景
之前接的一个需求,在创建店铺页面,根据用户的选择来判断到底是创建新系统店铺还是旧系统的店铺。一般情况下,都是根据前端传入的参数进行if else
判断。但既然都是Senior Java Developer
了,那就玩点花活吧,于是决定使用策略模型来实现。
实现
策略模式,大白话来说,就是不同的场景下使用不同的策略来完成任务。在我这个场景中,需要根据前端传入的不同参数来实现不同的开店策略。先定义一个开店策略,具体的逻辑由实现类实现,如下:
/**
* @author Reece
* @Description 策略接口
*/
public interface CreateShopStrategy {
/*
* 创建店铺
* @param reqVO
* @return com.example.demos.model.ShopVO
* @author Reece
* @date 2022/4/10 20:14:02
*/
ShopVO createShop(CreateShopReqVO reqVO);
/*
* 具体的策略类型
* @param
* @return java.lang.Integer
* @author Reece
*/
Integer getType();
}
然后就是策略集合,到底有多少种策略,使用枚举就可以了。
/**
* @author Reece
* @Description 策略集合
*/
@Getter
public enum StrategyType {
OLD(1,"旧系统"),
NEW(2,"新系统");
private final Integer type;
private final String desc;
StrategyType(Integer type, String desc) {
this.type = type;
this.desc = desc;
}
}
接下来就是具体的子类实现类了。
/**
* @author Reece
* @Description 旧系统的开店逻辑
*/
@Service
public class OldCreateShopImpl extends CreateShopStrategy {
@Override
public ShopVO createShop(CreateShopReqVO reqVO) {
return ShopVO.builder().shopName("OldCreateShopImpl").uid(reqVO.getUid()).id(new Random().nextLong()).build();
}
@Override
public Integer getType() {
return StrategyType.OLD.getType();
}
}
/**
* @author Reece
* @Description 新系统的开店逻辑
*/
@Service
public class NewCreateShopImpl extends CreateShopStrategy {
@Override
protected ShopVO createShop(CreateShopReqVO reqVO) {
return ShopVO.builder().shopName("NewCreateShopImpl").uid(reqVO.getUid()).id(new Random().nextLong()).build();
}
@Override
protected Integer getType() {
return StrategyType.NEW.getType();
}
}
好了,实现类都有了,策略模式的开发完成了。但是现在又有新的问题,前端传入了type
,难道还使用if(type==?)
来判断?策略模式没有之前,我用if else
来判断。策略模式有了,我还是用if else
来判断。那策略模式不就白写了么? 淡定,淡定,接下来就是工厂模式该出场的时候了。
所谓工厂模式即是在创建对象时对客户端屏蔽具体的创建逻辑,只通过接口来返回所需的具体对象。这里我们利用Spring
容器的自动注入来方便快捷地实现工厂模式。
/**
* @author Reece
* @Description
*/
@Component
public class CreateShopStrategyFactory implements ApplicationContextAware {
// 缓存
private static final Map<Integer, CreateShopStrategy> STRATEGY_MAP = new ConcurrentHashMap<>();
/**
* 根据不同的type返回具体的策略
*
* @param type
* @return com.example.demos.strategy.CreateShopStrategy
* @author Reece
* @date 2022/4/10 19:39:19
*/
public CreateShopStrategy get(Integer type) {
// 从缓存中获取具体的实现类
return STRATEGY_MAP.get(type);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// 获取容器中所有实现CreateShopStrategy的实现类
Map<String, CreateShopStrategy> strategyMap = applicationContext.getBeansOfType(CreateShopStrategy.class);
// 设置进缓存中
strategyMap.values().forEach(strategy -> STRATEGY_MAP.put(strategy.getType(), strategy));
}
}
验证
上面已经完成了策略模式,剩下就是验证策略模式是否成功。
/**
* @author Reece
* @Description
*/
@Service
public class ShopServiceImpl implements ShopService {
@Autowired
private CreateShopStrategyFactory shopStrategyFactory;
@Override
public ShopVO createShop(CreateShopReqVO reqVO) {
// 获取具体的实现策略
CreateShopStrategy createShopStrategy = shopStrategyFactory.get(reqVO.getType());
// 获取返回值
return createShopStrategy.createShop(reqVO);
}
}
/**
* @author Reece
* @Description
*/
@Controller
@RequestMapping("/shop")
public class ShopController {
@Autowired
private ShopService shopService;
@ResponseBody
@PostMapping("/createShop")
public ShopVO createShop(CreateShopReqVO reqVO) {
return shopService.createShop(reqVO);
}
}
启动SpringBoot
应用,传入不同的参数调用接口。
type
为1时,如下所示:
type
为2时,如下所示:
至此,策略模式已完成,详细的源码请点击demos查看