介绍

在策略模式(Strategy Pattern)中,一个类的行为可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
关键代码:实现同一个接口。
应用实例:

  1. 诸葛亮的锦囊妙计,每一个锦囊就是一个策略。
  2. 旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。

优点:

  1. 算法可以自由切换。
  2. 避免使用多重条件判断。
  3. 扩展性良好。

缺点:

  1. 策略类会增多。
  2. 所有策略类都需要对外暴露。

使用场景:

  1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
  2. 一个系统需要动态地在几种算法中选择一种。
  3. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

UML类图

image.png

策略模式核心接口

  1. package strategy.core;
  2. /**
  3. * @author anthony
  4. * @date 2021/1/17 3:05
  5. */
  6. public interface ProjectStrategy {
  7. /**
  8. * 策略模式抽象核心处理方法
  9. */
  10. void dealWithProject();
  11. }

策略模式不同的实现方式

竞价项目处理方式

  1. package strategy.core;
  2. /**
  3. * @author anthony
  4. * @date 2021/1/17 3:09
  5. */
  6. public class BidProjectStrategy implements ProjectStrategy {
  7. @Override
  8. public void dealWithProject() {
  9. System.out.println("竞价项目");
  10. }
  11. }

招标项目处理方式

  1. package strategy.core;
  2. /**
  3. * @author anthony
  4. * @date 2021/1/17 3:10
  5. */
  6. public class TenderProjectStrategy implements ProjectStrategy {
  7. @Override
  8. public void dealWithProject() {
  9. System.out.println("招标项目");
  10. }
  11. }

工程项目处理方式

  1. package strategy.core;
  2. /**
  3. * @author anthony
  4. * @date 2021/1/17 3:12
  5. */
  6. public class EngineeringProjectStrategy implements ProjectStrategy {
  7. @Override
  8. public void dealWithProject() {
  9. System.out.println("工程项目");
  10. }
  11. }

策略模式上下文来选取算法

  1. package strategy;
  2. import strategy.core.ProjectStrategy;
  3. import strategy.core.ProjectStrategyFactory;
  4. /**
  5. * @author anthony
  6. * @date 2021/1/17 3:34
  7. */
  8. public class ProjectStrategyContext {
  9. /**
  10. * 选择处理项目的方法
  11. * @param projectCode
  12. */
  13. public void selectProjectDealWith(int projectCode){
  14. ProjectStrategy projectStrategy = ProjectStrategyFactory.getInstance().create(projectCode);
  15. projectStrategy.dealWithProject();
  16. }
  17. }

枚举值

  1. package strategy;
  2. /**
  3. * @author anthony
  4. * @date 2021/1/17 3:06
  5. */
  6. public enum ProjectEnum {
  7. /**
  8. * 项目类别
  9. */
  10. BID(1, "竞价项目"),
  11. TENDER(2, "招标项目"),
  12. ENGINEERING(3, "工程项目")
  13. ;
  14. private final int code;
  15. private final String desc;
  16. ProjectEnum(int code, String desc) {
  17. this.code = code;
  18. this.desc = desc;
  19. }
  20. public int getCode() {
  21. return code;
  22. }
  23. public String getDesc() {
  24. return desc;
  25. }
  26. @Override
  27. public String toString() {
  28. return "ProjectEnum{" +
  29. "code=" + code +
  30. ", desc='" + desc + '\'' +
  31. '}';
  32. }
  33. }

使用工厂模式和单例模式来选取

  1. package strategy.core;
  2. import strategy.ProjectEnum;
  3. import java.util.Objects;
  4. import java.util.concurrent.ConcurrentHashMap;
  5. /**
  6. * @author anthony
  7. * @date 2021/1/17 3:13
  8. */
  9. public class ProjectStrategyFactory {
  10. private static ProjectStrategyFactory factory;
  11. private static ConcurrentHashMap<Integer, ProjectStrategy> strategyMap = new ConcurrentHashMap<>(16);
  12. static {
  13. strategyMap.put(ProjectEnum.BID.getCode(),new BidProjectStrategy());
  14. strategyMap.put(ProjectEnum.TENDER.getCode(),new TenderProjectStrategy());
  15. strategyMap.put(ProjectEnum.ENGINEERING.getCode(),new EngineeringProjectStrategy());
  16. }
  17. /**
  18. * 获取具体项目处理方式
  19. * @param payCode
  20. * @return
  21. */
  22. public ProjectStrategy create(int payCode){
  23. return strategyMap.get(payCode);
  24. }
  25. private ProjectStrategyFactory() {
  26. }
  27. public static ProjectStrategyFactory getInstance(){
  28. if (Objects.isNull(factory)){
  29. synchronized (ProjectStrategyFactory.class){
  30. if (Objects.isNull(factory)){
  31. factory = new ProjectStrategyFactory();
  32. }
  33. }
  34. }
  35. return factory;
  36. }
  37. }

客户端调用

  1. package strategy;
  2. /**
  3. * @author anthony
  4. * @date 2021/1/17 3:31
  5. */
  6. public class Client {
  7. public static void main(String[] args) {
  8. int projectCode = 1;
  9. ProjectStrategyContext context = new ProjectStrategyContext();
  10. context.selectProjectDealWith(projectCode);
  11. }
  12. }