strategy design pattern,定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够相互替换。
最常见的应用场景是拿来避免冗长的 if-else 或 switch 分支判断,主要是将 if else 的判断逻辑下放或存放在 Map 中以键值对的方式替代 if else,其中 Map 的 key 对应判断条件, value 则封装成策略替代进入判断条件的业务。
// 策略接口声明了某个算法各个不同版本间所共有的操作。上下文会使用该接口来// 调用有具体策略定义的算法。interface Strategy ismethod execute(a, b)// 具体策略会在遵循策略基础接口的情况下实现算法。该接口实现了它们在上下文// 中的互换性。class ConcreteStrategyAdd implements Strategy ismethod execute(a, b) isreturn a + bclass ConcreteStrategySubtract implements Strategy ismethod execute(a, b) isreturn a - bclass ConcreteStrategyMultiply implements Strategy ismethod execute(a, b) isreturn a * b// 上下文定义了客户端关注的接口。class Context is// 上下文会维护指向某个策略对象的引用。上下文不知晓策略的具体类。上下// 文必须通过策略接口来与所有策略进行交互。private strategy: Strategy// 上下文通常会通过构造函数来接收策略对象,同时还提供设置器以便在运行// 时切换策略。method setStrategy(Strategy strategy) isthis.strategy = strategy// 上下文会将一些工作委派给策略对象,而不是自行实现不同版本的算法。method executeStrategy(int a, int b) isreturn strategy.execute(a, b)// 客户端代码会选择具体策略并将其传递给上下文。客户端必须知晓策略之间的差// 异,才能做出正确的选择。class ExampleApplication ismethod main() is创建上下文对象。读取第一个数。读取最后一个数。从用户输入中读取期望进行的行为。if (action == addition) thencontext.setStrategy(new ConcreteStrategyAdd())if (action == subtraction) thencontext.setStrategy(new ConcreteStrategySubtract())if (action == multiplication) thencontext.setStrategy(new ConcreteStrategyMultiply())result = context.executeStrategy(First number, Second number)打印结果。
/*** The Context defines the interface of interest to clients.*/class Context {/*** @type {Strategy} The Context maintains a reference to one of the Strategy* objects. The Context does not know the concrete class of a strategy. It* should work with all strategies via the Strategy interface.*/private strategy: Strategy;/*** Usually, the Context accepts a strategy through the constructor, but also* provides a setter to change it at runtime.*/constructor(strategy: Strategy) {this.strategy = strategy;}/*** Usually, the Context allows replacing a Strategy object at runtime.*/public setStrategy(strategy: Strategy) {this.strategy = strategy;}/*** The Context delegates some work to the Strategy object instead of* implementing multiple versions of the algorithm on its own.*/public doSomeBusinessLogic(): void {// ...console.log('Context: Sorting data using the strategy (not sure how it\'ll do it)');const result = this.strategy.doAlgorithm(['a', 'b', 'c', 'd', 'e']);console.log(result.join(','));// ...}}/*** The Strategy interface declares operations common to all supported versions* of some algorithm.** The Context uses this interface to call the algorithm defined by Concrete* Strategies.*/interface Strategy {doAlgorithm(data: string[]): string[];}/*** Concrete Strategies implement the algorithm while following the base Strategy* interface. The interface makes them interchangeable in the Context.*/class ConcreteStrategyA implements Strategy {public doAlgorithm(data: string[]): string[] {return data.sort();}}class ConcreteStrategyB implements Strategy {public doAlgorithm(data: string[]): string[] {return data.reverse();}}/*** The client code picks a concrete strategy and passes it to the context. The* client should be aware of the differences between strategies in order to make* the right choice.*/const context = new Context(new ConcreteStrategyA());console.log('Client: Strategy is set to normal sorting.');context.doSomeBusinessLogic();console.log('');console.log('Client: Strategy is set to reverse sorting.');context.setStrategy(new ConcreteStrategyB());context.doSomeBusinessLogic();
