简体   繁体   English

这是否遵循策略设计模式

[英]Is this following the strategy design pattern

Me and my colleague have a disagreement about if this follows the strategy pattern or not.我和我的同事对于这是否遵循策略模式存在分歧。

We have a react component List which expects a "strategy" prop that has the following shape:我们有一个反应组件List ,它需要一个具有以下形状的“策略”道具:

interface ListStrategy {
  renderItem: (index: number) => React.ReactNode
  itemCount: number
}

We have some functions that create a "strategy" for rendering the list in a certain way.我们有一些函数可以创建以某种方式呈现列表的“策略”。 For instance we have the following strategy constructors.例如,我们有以下策略构造函数。

createGroupedListStrategy(...args: GroupedListStrategyArgs): ListStrategy
createFlatListStrategy(...args: FlatListStrategyArgs): ListStrategy
createTreeListStrategy(...args: TreeListStrategyArgs): ListStrategy

I found a lot of examples where the constructor of a strategy either expects no arguments, or expects the same arguments for every strategy.我发现了很多示例,其中策略的构造函数要么期望没有 arguments,要么期望每个策略都使用相同的 arguments。 But the constructors above each expect different arguments.但是上面每个构造函数都期望不同的 arguments。 createGroupedListStrategy expects as an option a function that can be used inside the strategy to match items to their group. createGroupedListStrategy期望作为一个选项 function 可以在策略内部使用以将项目与其组匹配。 createTreeListStrategy expects as an option a function that it can use to access the children of an item. createTreeListStrategy期望作为一个选项 function 可用于访问项目的子项。

Because the constructors are so different, my colleague started to doubt if these strategies are interchangeable in the sense that the definition of the strategy pattern talks about.由于构造函数如此不同,我的同事开始怀疑这些策略在策略模式的定义所谈论的意义上是否可以互换。 But my view is that once the strategies are instantiated, they can be interchanged without a problem.但我的观点是,一旦策略被实例化,它们就可以毫无问题地互换。

Can anyone clear this up?任何人都可以清除这个吗? I'm really curious.我真的很好奇。

The constructors for the strategies don't have any relevance for whether something is or isn't a strategy.策略的构造函数与某事物是否是策略没有任何关系。 The goal of the strategy pattern is to extract an operation to be independant from the class and to allow you to determine how a class behaves, without altering it.策略模式的目标是提取一个独立于 class 的操作,并允许您确定class的行为方式,而无需更改它。

Consider the following, we want to make a trivial "calculator" that takes two values and operates with them.考虑以下情况,我们想要制作一个简单的“计算器”,它接受两个值并使用它们进行运算。 It then displays that result in some way.然后它以某种方式显示该结果。 We want to extract the logic for:我们要提取以下逻辑:

  • the calculation - how two numbers are handled计算 -如何处理两个数字
  • the display - how the result is shown显示 - 如何显示结果

This would mean that we can change how the calculator works without altering the class itself.这意味着我们可以在不改变 class 本身的情况下改变计算器的工作方式。 So, we extract two strategies:因此,我们提取了两种策略:

interface CalculationStrategy {
    doMaths: (a: number, b: number) => number
}

interface DisplayStrategy {
    show: (num: number) => void
}

And we could supply multiple implementations:我们可以提供多种实现:

 //calculation strategies class AddStrategy { doMaths(a, b) { return a + b; } } class MultiplyByConstantStrategy { constructor(x) { this.x = x; } doMaths(a, b) { return (a + b) * this.x; } } //display strategies class ConsoleDisplayStrategy { show(num) { console.log(num.toFixed(2)) } } class HTMLDisplayStrategy { constructor(elementSelector) { this.inputElement = document.querySelector(elementSelector); } show(num) { this.inputElement.value = num; } } //calculate class class Calculate { constructor(operationHandler, displayHandler) { this.operationHandler = operationHandler; this.displayHandler = displayHandler; } calculate(a, b) { const result = this.operationHandler.doMaths(a, b); this.displayHandler.show(result); } } /* usage */ //calculate the total for a bill + tip const tip = new Calculate( new MultiplyByConstantStrategy(1.15), new HTMLDisplayStrategy("#totalWithTip") ); document.querySelector("#billTotal").addEventListener("click", () => { const coffee = Number(document.querySelector("#coffeePrice").value); const bagel = Number(document.querySelector("#bagelPrice").value); tip.calculate(coffee, bagel); }); //just display a calculation on the page const showAdd = new Calculate( new AddStrategy(), new HTMLDisplayStrategy("#addResult") ); showAdd.calculate(2, 8); //print a sum const printAdd = new Calculate( new AddStrategy(), new ConsoleDisplayStrategy() ); document.querySelector("#printSum").addEventListener("click", () => { const a = Number(document.querySelector("#a").value); const b = Number(document.querySelector("#b").value); printAdd.calculate(a, b); });
 .as-console-wrapper { /* prevent the console output from covering the page */ position: initial;important; }
 <pre>MultiplyByConstantStrategy + HTMLDisplayStrategy</pre> <div> <label for="coffeePrice">Price for coffee:</label> <input id="coffeePrice" value="2" type="number" /> </div> <div> <label for="bagelPrice">Price for bagel:</label> <input id="bagelPrice" value="8" type="number" /> </div> <div> <label for="totalWithTip">You owe:</label> <input id="totalWithTip" readonly/> </div> <button id="billTotal">Bill please!</button> <hr/> <pre>AddStrategy + HTMLDisplayStrategy</pre> <div> <label for="addResult">2 + 8 = </label> <input id="addResult" readonly/> </div> <hr/> <pre>AddStrategy + ConsoleDisplayStrategy</pre> <div> <input id="a" value="2" type="number" /> + <input id="b" value="8" type="number" /> </div> <button id="printSum">print the sum</button>

The goal is reached here.目标在这里达到。 We've successfully decoupled the calculation and display.我们已经成功地解耦了计算和显示。 We can alter each one without having to change the other or the Calculate class.我们可以更改每一个,而无需更改另一个或Calculate class。 And this is what the strategy pattern tries to solve.这就是策略模式试图解决的问题。 The fact that the strategies are constructed with different parameters is irrelevant for this outcome.使用不同参数构建策略的事实与此结果无关。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM