这两天学习了策略模式和模板模式,总结一下这两种模式。
策略模式的使用场景主要是同一类行为的不同实现上,如
策略模式主要有下面这3个类
下面举一个具体的例子,在抽奖的时候,有不同的抽奖策略,下面这个例子有两个抽奖策略的实现
- public interface IDrawAlgorithm {
- /**
- * SecureRandom 生成随机数,索引到对应的奖品信息返回结果
- *
- * @param strategyId 策略ID
- * @param excludeAwardIds 排除掉已经不能作为抽奖的奖品ID,留给风控和空库存使用
- * @return 中奖结果
- */
- String randomDraw(Long strategyId, List<String> excludeAwardIds);
-
- }
- @Component("singleRateRandomDrawAlgorithm")
- public class SingleRateRandomDrawAlgorithm extends BaseAlgorithm {
-
- @Override
- public String randomDraw(Long strategyId, List<String> excludeAwardIds) {
- // 策略1实现
- return awardId;
- }
-
- }
- @Component("entiretyRateRandomDrawAlgorithm")
- public class EntiretyRateRandomDrawAlgorithm extends BaseAlgorithm {
-
- @Override
- public String randomDraw(Long strategyId, List<String> excludeAwardIds) {
- // 策略2实现
- // 返回中奖结果
- return awardId;
- }
-
- }
- public class StrategyContext {
- private IDrawAlgorithm drawAlgorithm;
-
- public StrategyContext(IDrawAlgorithm drawAlgorithm) {
- this.drawAlgorithm = drawAlgorithm;
- }
-
- public String randomDraw(Long strategyId, List<String> excludeAwardIds) {
- return drawAlgorithm.randomDraw(strategyId, excludeAwardIds);
- }
- }
测试:
- public static void main(String[] args) {
- StrategyContext strategyContext = new StrategyContext(new SingleRateRandomDrawAlgorithm());
- strategyContext.randomDraw(10001L, new ArrayList<>());
- }
当一个事情可以流程化来做的时候,可以使用模板模式来开发,模版模式中有下面几个流程
下面是一个抽奖的例子,将抽奖的流程固定在模板抽象类中
- public interface IDrawExec {
-
- /**
- * 抽奖方法
- * @param req 抽奖参数;用户ID、策略ID
- * @return 中奖结果
- */
- DrawResult doDrawExec(DrawReq req);
-
- }
这里面获取不在抽奖范围内的列表和执行抽奖算法步骤是包含业务逻辑的,这些可以在子类中实现,公共的放在抽象类中。
- public abstract class AbstractDrawBase extends DrawStrategySupport implements IDrawExec {
-
- private Logger logger = LoggerFactory.getLogger(AbstractDrawBase.class);
-
- @Override
- public DrawResult doDrawExec(DrawReq req) {
- // 1. 获取抽奖策略
- StrategyRich strategyRich = super.queryStrategyRich(req.getStrategyId());
- Strategy strategy = strategyRich.getStrategy();
-
- // 2. 校验抽奖策略是否已经初始化到内存
- this.checkAndInitRateData(req.getStrategyId(), strategy.getStrategyMode(), strategyRich.getStrategyDetailList());
-
- // 3. 获取不在抽奖范围内的列表,包括:奖品库存为空、风控策略、临时调整等
- List<String> excludeAwardIds = this.queryExcludeAwardIds(req.getStrategyId());
-
- // 4. 执行抽奖算法
- String awardId = this.drawAlgorithm(req.getStrategyId(), drawAlgorithmGroup.get(strategy.getStrategyMode()), excludeAwardIds);
-
- // 5. 包装中奖结果
- return buildDrawResult(req.getuId(), req.getStrategyId(), awardId);
- }
- public class DrawExecImpl extends AbstractDrawBase {
-
- private Logger logger = LoggerFactory.getLogger(DrawExecImpl.class);
-
- @Override
- protected List<String> queryExcludeAwardIds(Long strategyId) {
- // 获取不在抽奖范围内的列表逻辑
- return awardList;
- }
-
- @Override
- protected String drawAlgorithm(Long strategyId, IDrawAlgorithm drawAlgorithm, List<String> excludeAwardIds) {
- // 抽奖逻辑
- return isSuccess ? awardId : null;
- }
-
- }