策略模式

定义:指对一系列的算法定义,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

简易UML图

第8节:策略模式(Strategy Pattern) - 图1

需求分析

每当节假日来临,众多商品就会进行相应折扣,以此来吸引客户,不同的节日,有不同寓意,也就是说,不同的节日,某些商品将赋予特定价值,而这时带来了巨大的需求,市场供求过大。为竞争其他商户,为自家商品迎来订单,这时就需要饥饿效应,玩打折来吸引客户。
可到底是哪些商品进行打折,以及每个商品需要打多少折扣,既保证吸引客户,又能保证赚钱。这就需要为商品分类进行算法得出,同时在业务中,我们很可能要写异常多的类,如果杂糅在一起,那对于维护极不方便。
而策略模式,就是可以将每个单独商品分类价格处理,避免代码的耦合性太高。

具体实现

第8节:策略模式(Strategy Pattern) - 图2

定义接口

  1. package com.test.strategy;
  2. import com.test.domain.Goods;
  3. /**
  4. * 策略方法
  5. * @author 12134
  6. *
  7. */
  8. public interface IJRStrategy {
  9. /**
  10. * 活动,每个活动都有特定的商品奖励活动,该商品活动根据算法计算出来
  11. */
  12. String activity(Goods goods);
  13. }

自定义接口

用于判断该活动属于那个节日。

  1. package com.test.annotation;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. import com.test.enums.ActivityJREnum;
  8. /**
  9. * 节日商品注解
  10. * @author 12134
  11. *
  12. */
  13. @Documented
  14. @Target(ElementType.TYPE)
  15. @Retention(RetentionPolicy.RUNTIME)
  16. public @interface JRGoodSource {
  17. ActivityJREnum value();
  18. }

定义节日枚举类

  1. package com.test.enums;
  2. public enum ActivityJREnum {
  3. /**
  4. * 七夕节
  5. */
  6. QIXIJIE(1,"七夕节"),
  7. /**
  8. * 劳动节
  9. */
  10. LAODONGJIE(2,"劳动节"),
  11. /**
  12. * 元宵节
  13. */
  14. YUANXIAOJIE(3,"元宵节");
  15. private Integer code;
  16. private String name;
  17. ActivityJREnum() {
  18. }
  19. ActivityJREnum(Integer code, String name) {
  20. this.code = code;
  21. this.name = name;
  22. }
  23. public Integer getCode() {
  24. return code;
  25. }
  26. public String getName() {
  27. return name;
  28. }
  29. }

定义接口实现类

也是算法和业务处理的地方。

  1. package com.test.strategy.impl;
  2. import java.text.DecimalFormat;
  3. import com.test.annotation.JRGoodSource;
  4. import com.test.domain.Goods;
  5. import com.test.enums.ActivityJREnum;
  6. import com.test.strategy.IJRStrategy;
  7. /**
  8. * 劳动节
  9. * @author 12134
  10. *
  11. */
  12. @JRGoodSource(ActivityJREnum.LAODONGJIE)
  13. public class LaoDongJR implements IJRStrategy{
  14. /**
  15. * 商品的价格打折处理
  16. */
  17. @Override
  18. public String activity(Goods goods) {
  19. // 劳动节特定商品打七折
  20. DecimalFormat df =new DecimalFormat("#.00");
  21. String result = df.format(goods.getPrice()*0.7);
  22. return result;
  23. }
  24. }
  1. package com.test.strategy.impl;
  2. import java.text.DecimalFormat;
  3. import com.test.annotation.JRGoodSource;
  4. import com.test.domain.Goods;
  5. import com.test.enums.ActivityJREnum;
  6. import com.test.strategy.IJRStrategy;
  7. /**
  8. * 七夕节 情侣专用的商品 算法得出:销量最好的,玫瑰、巧克力、酒店等等商品
  9. *
  10. * @author 12134
  11. *
  12. */
  13. @JRGoodSource(ActivityJREnum.QIXIJIE)
  14. public class QixiJR implements IJRStrategy {
  15. /**
  16. * 商品的打折处理
  17. * @param price 商品价格
  18. */
  19. @Override
  20. public String activity(Goods goods) {
  21. // 情人节特定商品打八折
  22. DecimalFormat df =new DecimalFormat("#.00");
  23. String result = df.format(goods.getPrice()*0.8);
  24. return result;
  25. }
  26. }
  1. package com.test.strategy.impl;
  2. import java.text.DecimalFormat;
  3. import com.test.annotation.JRGoodSource;
  4. import com.test.domain.Goods;
  5. import com.test.enums.ActivityJREnum;
  6. import com.test.strategy.IJRStrategy;
  7. /**
  8. * 元宵节
  9. *
  10. * @author 12134
  11. *
  12. */
  13. @JRGoodSource(ActivityJREnum.YUANXIAOJIE)
  14. public class YuanXiaoJR implements IJRStrategy {
  15. /**
  16. * 商品的打折处理
  17. */
  18. @Override
  19. public String activity(Goods goods) {
  20. // 元宵节特定商品打九折
  21. DecimalFormat df =new DecimalFormat("#.00");
  22. String result = df.format(goods.getPrice()*0.9);
  23. return result;
  24. }
  25. }

定义pojo

  1. package com.test.domain;
  2. public class Goods {
  3. /**
  4. * 商品编号
  5. */
  6. private String no;
  7. /**
  8. * 商品名称
  9. */
  10. private String name;
  11. /**
  12. * 商品价格
  13. */
  14. private Double price;
  15. /**
  16. * 本次活动名 1:七夕节,2:劳动节,3:元宵节
  17. */
  18. private Integer sourceFlg;
  19. /**
  20. * 活动折扣和提示信息
  21. */
  22. private Discount discount;
  23. public String getNo() {
  24. return no;
  25. }
  26. public void setNo(String no) {
  27. this.no = no;
  28. }
  29. public String getName() {
  30. return name;
  31. }
  32. public void setName(String name) {
  33. this.name = name;
  34. }
  35. public Double getPrice() {
  36. return price;
  37. }
  38. public void setPrice(Double price) {
  39. this.price = price;
  40. }
  41. public Integer getSourceFlg() {
  42. return sourceFlg;
  43. }
  44. public void setSourceFlg(Integer sourceFlg) {
  45. this.sourceFlg = sourceFlg;
  46. }
  47. public Discount getDiscount() {
  48. return discount;
  49. }
  50. public void setDiscount(Discount discount) {
  51. this.discount = discount;
  52. }
  53. public Goods() {
  54. super();
  55. }
  56. public Goods(String no, String name, Double price, Integer sourceFlg) {
  57. super();
  58. this.no = no;
  59. this.name = name;
  60. this.price = price;
  61. this.sourceFlg = sourceFlg;
  62. }
  63. public Goods(String no, String name, Double price, Integer sourceFlg, Discount discount) {
  64. super();
  65. this.no = no;
  66. this.name = name;
  67. this.price = price;
  68. this.sourceFlg = sourceFlg;
  69. this.discount = discount;
  70. }
  71. @Override
  72. public String toString() {
  73. return "Goods [no=" + no + ", name=" + name + ", price=" + price + ", sourceFlg=" + sourceFlg + ", discount="
  74. + discount + "]";
  75. }
  76. }
  1. package com.test.domain;
  2. import java.io.Serializable;
  3. /**
  4. * 商品折扣
  5. *
  6. * @author 12134
  7. *
  8. */
  9. public class Discount implements Serializable {
  10. private static final long serialVersionUID = 1L;
  11. /**
  12. * 折扣编号
  13. */
  14. private int no;
  15. /**
  16. * 折扣信息
  17. */
  18. private String message;
  19. /**
  20. * 节日提示信息
  21. */
  22. private String jieRi;
  23. public int getNo() {
  24. return no;
  25. }
  26. public void setNo(int no) {
  27. this.no = no;
  28. }
  29. public String getMessage() {
  30. return message;
  31. }
  32. public void setMessage(String message) {
  33. this.message = message;
  34. }
  35. public String getJieRi() {
  36. return jieRi;
  37. }
  38. public void setJieRi(String jieRi) {
  39. this.jieRi = jieRi;
  40. }
  41. public Discount(int no, String message, String jieRi) {
  42. super();
  43. this.no = no;
  44. this.message = message;
  45. this.jieRi = jieRi;
  46. }
  47. public Discount() {
  48. super();
  49. }
  50. @Override
  51. public String toString() {
  52. return "Discount [no=" + no + ", message=" + message + ", jieRi=" + jieRi + "]";
  53. }
  54. }
  1. package com.test.domain;
  2. import java.io.Serializable;
  3. public class ResponseMessage implements Serializable {
  4. private static final long serialVersionUID = 1L;
  5. private Integer code;
  6. private Object data;
  7. private String msg;
  8. public Integer getCode() {
  9. return code;
  10. }
  11. public void setCode(Integer code) {
  12. this.code = code;
  13. }
  14. public Object getData() {
  15. return data;
  16. }
  17. public void setData(Object data) {
  18. this.data = data;
  19. }
  20. public String getMsg() {
  21. return msg;
  22. }
  23. public void setMsg(String msg) {
  24. this.msg = msg;
  25. }
  26. public ResponseMessage(Integer code, Object data, String msg) {
  27. super();
  28. this.code = code;
  29. this.data = data;
  30. this.msg = msg;
  31. }
  32. public ResponseMessage() {
  33. super();
  34. }
  35. @Override
  36. public String toString() {
  37. return "ResponseMessage [code=" + code + ", data=" + data + ", msg=" + msg + "]";
  38. }
  39. }

定义处理接口调用

  1. package com.test.strategy.context;
  2. import java.util.List;
  3. import java.util.Map;
  4. import java.util.concurrent.ConcurrentHashMap;
  5. import com.test.domain.Goods;
  6. import com.test.strategy.IJRStrategy;
  7. public class JRSimpleContext {
  8. private final Map<Integer, IJRStrategy> strategyMap = new ConcurrentHashMap<>();
  9. /**
  10. * 构造函数
  11. *
  12. * @param strategyMap
  13. */
  14. public JRSimpleContext(Map<Integer, IJRStrategy> strategyMap) {
  15. this.strategyMap.clear();
  16. strategyMap.forEach((k, v) -> this.strategyMap.put(k, v));
  17. }
  18. /**
  19. * 商品订单编号处理
  20. *
  21. * @param requestId
  22. * @return
  23. */
  24. public List<Goods> getSource(List<Goods> goodsInfo) {
  25. System.out.println(strategyMap);
  26. for (int i = 0; i < goodsInfo.size(); i++) {
  27. Goods goods2 = goodsInfo.get(i);
  28. // 如果订单商品编号不为空
  29. if (strategyMap.get(goodsInfo.get(i).getSourceFlg()) != null) {
  30. // 获取该活动的价格
  31. String price = strategyMap.get(goodsInfo.get(i).getSourceFlg()).activity(goods2);
  32. goods2.setPrice(Double.valueOf(price));
  33. } else {
  34. System.out.println("你选购的商品不符合本次活动,暂不享受优惠,感谢你的使用!");
  35. }
  36. }
  37. return goodsInfo;
  38. }
  39. }

定义主方法

  1. package com.test;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.concurrent.ConcurrentHashMap;
  5. import com.test.domain.Discount;
  6. import com.test.domain.Goods;
  7. import com.test.domain.ResponseMessage;
  8. import com.test.enums.ActivityJREnum;
  9. import com.test.strategy.IJRStrategy;
  10. import com.test.strategy.context.JRSimpleContext;
  11. import com.test.strategy.impl.LaoDongJR;
  12. import com.test.strategy.impl.QixiJR;
  13. import com.test.strategy.impl.YuanXiaoJR;
  14. public class Main {
  15. private static JRSimpleContext jrSimpleContext;
  16. public static void main(String[] args) {
  17. List<Goods> goodsInfo = new ArrayList<Goods>();
  18. Goods goods1 = new Goods("1", "玫瑰", 888.0, 1);
  19. Goods goods2 = new Goods("2", "巧克力", 999.0, 1);
  20. Goods goods3 = new Goods("3", "苹果", 999.0, 2);
  21. goodsInfo.add(goods1);
  22. goodsInfo.add(goods2);
  23. goodsInfo.add(goods3);
  24. // 申明折扣
  25. Discount discount = null;
  26. // 申明节日策略
  27. IJRStrategy ijrStrategy = null;
  28. // 创建返回提示内容
  29. StringBuilder sb =new StringBuilder();
  30. ConcurrentHashMap<Integer, IJRStrategy> concurrentHashMap = new ConcurrentHashMap<>();
  31. for (int i = 0; i < goodsInfo.size(); i++) {
  32. Integer sourceFlg = goodsInfo.get(i).getSourceFlg();
  33. if ( ActivityJREnum.QIXIJIE.getCode().equals(sourceFlg)) {
  34. ijrStrategy = new QixiJR();
  35. } else if (ActivityJREnum.LAODONGJIE.getCode().equals(sourceFlg)) {
  36. ijrStrategy = new LaoDongJR();
  37. } else if (ActivityJREnum.YUANXIAOJIE.getCode().equals(sourceFlg)) {
  38. ijrStrategy = new YuanXiaoJR();
  39. } else {
  40. // 不处理
  41. }
  42. concurrentHashMap.put(sourceFlg, ijrStrategy);
  43. // 获取商品折扣信息
  44. if (sourceFlg!=null) {
  45. discount = getDiscount(sourceFlg);
  46. }
  47. // 每个商品对应的折扣
  48. goodsInfo.get(i).setDiscount(discount);
  49. }
  50. jrSimpleContext = new JRSimpleContext(concurrentHashMap);
  51. List<Goods> source = jrSimpleContext.getSource(goodsInfo);
  52. sb.append(source);
  53. ResponseMessage rMessage = new ResponseMessage();
  54. rMessage.setCode(200);
  55. rMessage.setData(sb);
  56. rMessage.setMsg("请求成功!");
  57. System.out.println(rMessage);
  58. }
  59. /**
  60. * 判断属于那个活动
  61. *
  62. * @return
  63. */
  64. public static Discount getDiscount(Integer sourceFlg) {
  65. Discount discount = new Discount();
  66. // 这里还可以更加仔细的衍生下去,对单独的商品进行对应商品折扣判断
  67. if (ActivityJREnum.QIXIJIE.getCode().equals(sourceFlg)) {
  68. // 返回对应商品的折扣
  69. discount.setNo(8);
  70. discount.setMessage("八折");
  71. discount.setJieRi("七夕节专属情侣商品特供:");
  72. } else if (ActivityJREnum.LAODONGJIE.getCode().equals(sourceFlg)) {
  73. discount.setNo(9);
  74. discount.setMessage("九折");
  75. discount.setJieRi("劳动节专属商务商品特供:");
  76. } else if (ActivityJREnum.LAODONGJIE.getCode().equals(sourceFlg)) {
  77. discount.setNo(7);
  78. discount.setMessage("七折");
  79. discount.setJieRi("元宵节专属家庭商品特供:");
  80. } else {
  81. // 不处理
  82. }
  83. return discount;
  84. }
  85. }

执行结果

ResponseMessage [code=200, data=[Goods [no=1, name=玫瑰, price=710.4, sourceFlg=1, discount=Discount [no=8, message=八折, jieRi=七夕节专属情侣商品特供:]], Goods [no=2, name=巧克力, price=799.2, sourceFlg=1, discount=Discount [no=8, message=八折, jieRi=七夕节专属情侣商品特供:]], Goods [no=3, name=苹果, price=699.3, sourceFlg=2, discount=Discount [no=9, message=九折, jieRi=劳动节专属商务商品特供:]]], msg=请求成功!]