strategy design pattern,定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够相互替换。

最常见的应用场景是拿来避免冗长的 if-else 或 switch 分支判断,主要是将 if else 的判断逻辑下放或存放在 Map 中以键值对的方式替代 if else,其中 Map 的 key 对应判断条件, value 则封装成策略替代进入判断条件的业务。

  1. // 策略接口声明了某个算法各个不同版本间所共有的操作。上下文会使用该接口来
  2. // 调用有具体策略定义的算法。
  3. interface Strategy is
  4. method execute(a, b)
  5. // 具体策略会在遵循策略基础接口的情况下实现算法。该接口实现了它们在上下文
  6. // 中的互换性。
  7. class ConcreteStrategyAdd implements Strategy is
  8. method execute(a, b) is
  9. return a + b
  10. class ConcreteStrategySubtract implements Strategy is
  11. method execute(a, b) is
  12. return a - b
  13. class ConcreteStrategyMultiply implements Strategy is
  14. method execute(a, b) is
  15. return a * b
  16. // 上下文定义了客户端关注的接口。
  17. class Context is
  18. // 上下文会维护指向某个策略对象的引用。上下文不知晓策略的具体类。上下
  19. // 文必须通过策略接口来与所有策略进行交互。
  20. private strategy: Strategy
  21. // 上下文通常会通过构造函数来接收策略对象,同时还提供设置器以便在运行
  22. // 时切换策略。
  23. method setStrategy(Strategy strategy) is
  24. this.strategy = strategy
  25. // 上下文会将一些工作委派给策略对象,而不是自行实现不同版本的算法。
  26. method executeStrategy(int a, int b) is
  27. return strategy.execute(a, b)
  28. // 客户端代码会选择具体策略并将其传递给上下文。客户端必须知晓策略之间的差
  29. // 异,才能做出正确的选择。
  30. class ExampleApplication is
  31. method main() is
  32. 创建上下文对象。
  33. 读取第一个数。
  34. 读取最后一个数。
  35. 从用户输入中读取期望进行的行为。
  36. if (action == addition) then
  37. context.setStrategy(new ConcreteStrategyAdd())
  38. if (action == subtraction) then
  39. context.setStrategy(new ConcreteStrategySubtract())
  40. if (action == multiplication) then
  41. context.setStrategy(new ConcreteStrategyMultiply())
  42. result = context.executeStrategy(First number, Second number)
  43. 打印结果。
  1. /**
  2. * The Context defines the interface of interest to clients.
  3. */
  4. class Context {
  5. /**
  6. * @type {Strategy} The Context maintains a reference to one of the Strategy
  7. * objects. The Context does not know the concrete class of a strategy. It
  8. * should work with all strategies via the Strategy interface.
  9. */
  10. private strategy: Strategy;
  11. /**
  12. * Usually, the Context accepts a strategy through the constructor, but also
  13. * provides a setter to change it at runtime.
  14. */
  15. constructor(strategy: Strategy) {
  16. this.strategy = strategy;
  17. }
  18. /**
  19. * Usually, the Context allows replacing a Strategy object at runtime.
  20. */
  21. public setStrategy(strategy: Strategy) {
  22. this.strategy = strategy;
  23. }
  24. /**
  25. * The Context delegates some work to the Strategy object instead of
  26. * implementing multiple versions of the algorithm on its own.
  27. */
  28. public doSomeBusinessLogic(): void {
  29. // ...
  30. console.log('Context: Sorting data using the strategy (not sure how it\'ll do it)');
  31. const result = this.strategy.doAlgorithm(['a', 'b', 'c', 'd', 'e']);
  32. console.log(result.join(','));
  33. // ...
  34. }
  35. }
  36. /**
  37. * The Strategy interface declares operations common to all supported versions
  38. * of some algorithm.
  39. *
  40. * The Context uses this interface to call the algorithm defined by Concrete
  41. * Strategies.
  42. */
  43. interface Strategy {
  44. doAlgorithm(data: string[]): string[];
  45. }
  46. /**
  47. * Concrete Strategies implement the algorithm while following the base Strategy
  48. * interface. The interface makes them interchangeable in the Context.
  49. */
  50. class ConcreteStrategyA implements Strategy {
  51. public doAlgorithm(data: string[]): string[] {
  52. return data.sort();
  53. }
  54. }
  55. class ConcreteStrategyB implements Strategy {
  56. public doAlgorithm(data: string[]): string[] {
  57. return data.reverse();
  58. }
  59. }
  60. /**
  61. * The client code picks a concrete strategy and passes it to the context. The
  62. * client should be aware of the differences between strategies in order to make
  63. * the right choice.
  64. */
  65. const context = new Context(new ConcreteStrategyA());
  66. console.log('Client: Strategy is set to normal sorting.');
  67. context.doSomeBusinessLogic();
  68. console.log('');
  69. console.log('Client: Strategy is set to reverse sorting.');
  70. context.setStrategy(new ConcreteStrategyB());
  71. context.doSomeBusinessLogic();

参考资料

  1. 策略模式
  2. 60 | 策略模式(上):如何避免冗长的if-else/switch分支判断代码?
  3. 策略模式 —- 修言