策略模式和访客模式有什么区别?
我很难理解这两种设计模式。
您能否给我上下文信息或示例,以便我可以得到清晰的想法并能够映射两者之间的差异。
谢谢。
I have trouble understanding these two design patterns.
Can you please give me contextual information or an example so I can get a clear idea and be able to map the difference between the two of them.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
策略模式类似于1:多关系。当存在一种类型的对象并且我想对其应用多个操作时,我使用策略模式。例如,如果我有一个封装视频剪辑的 Video 类,我可能想以不同的方式压缩它。所以我创建了一堆策略类:
等等。
我认为访问者模式是一种多:多关系。假设我的应用程序不仅包含视频,还包含音频剪辑。如果我坚持使用策略模式,我必须复制我的压缩类 - 一个用于视频,一个用于音频:
依此类推...
如果我切换到访问者模式,我就没有复制策略类。我通过添加方法来实现我的目标:
[更新:使用Java]
我在 Java 应用程序中使用了访问者模式。结果与上面描述的有点不同。这是此示例的 Java 版本。
现在要访问的接口和类:
The strategy pattern is like a 1:many relationship. When there is one type of object and I want to apply multiple operations to it, I use the strategy pattern. For example, if I have a Video class that encapsulates a video clip, I might want to compress it in different ways. So I create a bunch of strategy classes:
and so on.
I think of the visitor pattern as a many:many relationship. Let's say my application grows to to include not just video, but audio clips as well. If I stick with the strategy pattern, I have to duplicate my compression classes-- one for video and one for audio:
and so on...
If I switch to the visitor pattern, I do not have to duplicate the strategy classes. I achieve my goal by adding methods:
[UPDATE: with Java]
I used the visitor pattern in a Java app. It came out a little different than described above. Here is a Java version for this example.
And now the interface and class to be visited:
策略模式用于将各种算法公开给标准化接口。一个典型的例子是排序实用程序,它允许用户(程序员)在通过相同接口调用的各种排序算法之间进行选择。
访问者模式存在于不同的层面。它详细介绍了一种机制,通过该机制,对象可以接受对另一个对象(访问者)的引用,该对象公开目标对象可以调用其自身的预定接口。当然,不同的访问者会呈现相同的界面,但有不同的实现。
回到我们的示例,排序算法的集合可以通过策略模式或访问者模式来实现。
使用策略方法,每个算法都呈现相同的接口,并以目标对象数组作为参数。对于访问者模式,目标数组将采用“访问”算法作为参数。在这种情况下,在我们的示例中,目标将“accept()”选定的访问者,并在调用目标的排序方法时调用其“visit()”方法。
同一枚硬币的两面……
这有道理吗?
A Strategy pattern is used to expose various algorithms to a standardized interface. A typical example could be a sort utility that would let the user (programmer) choose between various sort algorithms each called via the same interface.
A Visitor pattern lives at a different level. It details a mechanism with which objects can accept a reference to another object (the visitor) which exposes a predetermined interface that the target object can call upon itself. Of course, different visitors would present the same interface but have different implementations.
Coming back to our example, a collection of sort algorithms could be implemented either via the Strategy pattern or via the Visitor pattern.
With the Strategy method, each algorithm presents the same interface and takes arrays of target objects as parameters for example. With the Visitor pattern, it would be the target array that takes the "visiting" algorithm as a parameter. In this case, the target would "accept()" the selected visitor and call its "visit()" method upon invocation of the target's sort method in our example.
Two sides of the same coin...
Does this make sense?
访问者是一种策略,但具有多种方法,并且允许双重调度。访问者还允许在运行时在两个具体对象之间进行安全绑定。
注意:这是用 Java 编写的示例。例如,C# 引入了
dynamic
关键字,因此双重调度的示例在 C# 中没有用处。策略模式
考虑以下示例和输出:
如果策略和主题之间没有直接关系,则
Strategy
模式可以正常工作。例如,我们不希望发生以下情况:因此在这种情况下我们可以使用访问者模式。
访问者
问题
考虑下面的代码:
输出为
Applying a very Specific Porsche Repair
。问题是这一行不是抽象的,而是具体的:
我们想把它写成(或者在构造函数中注入 Car 的实例,我们想应用
依赖倒置原则
):但是当我们更改此行,输出将是:
不是我们想要的!
解决方案;使用双重调度(和访问者模式)
由于方法重载,访问者和主题(汽车)之间存在具体的绑定。保时捷不可能像法拉利一样被修理,因为它使用方法重载。我们还通过实现此方法解决了前面解释的问题(我们不能使用
Dependency Inversion
):this
引用将返回对象的具体类型,而不是抽象类型(汽车)类型。A Visitor is a strategy but with multiple methods and it allows Double dispatch. The Visitor also allows for safe binding between two concrete objects at runtime.
Note: This is an example written in Java. For example C# introduced the
dynamic
keyword, therefor the example of double dispatch is not useful in C#.Strategy pattern
Consider the following example and the output:
The
Strategy
pattern is working fine if there is no direct relationship between the strategy and the subject. For example, we don't want the following to happen:So in this case we can use the visitor pattern.
Visitor
The problem
Consider the code below:
The output is
Applying a very specific Porsche repair
.The problem is that this line is not abstract, but concrete:
We want to write it as (or inject an instance of Car in the constructor, we want to apply the
Dependency Inversion Principle
):But when we change this line, the output will be:
Not what we want!
The solution; using double dispatch (and the Visitor pattern)
Because of method overloading, there is a concrete binding between the visitor and the subject (Car). There is no way a Porsche can be repaired as a Ferrari, since it uses method overloading. Also we solved the previously explained problem (that we cannot use
Dependency Inversion
), by implementing this method:The
this
reference will return the concrete type of the object, not the abstract (Car) type.访问者就像一夜情——你在调用接受函数时创建它,然后它们分开,访问者可以从内存中清除,它不会为使用它的类占用任何空间。
该策略就像婚姻 - 您创建了对象,它存在于使用它的类中,占用内存,有一个房间并在早上给自己煮咖啡:)。
当然,他们可以离婚并转入另一个阶层,但该阶层也将生活在其所有者的环境中。
希望它能帮助你记住:)
The visitor is like a one-night stand - you create it when you call the accept function and then they get separated and the visitor can be cleaned from the memory, it doesn't take any room for the class that use it.
The strategy is like a marriage - you create the object, it lives in the class that uses it, takes memory, has a room and makes itself a coffee in the morning :) .
Of course they can get a divorce and switch to another class but that class would also live in its owner's context.
Hope it helps you remember :)
决定性的区别在于,Visitor 使用运算符重载为元素的子类提供不同的行为。它知道它正在处理或访问的事物类型。
与此同时,策略将在其所有实现中保持一致的接口。
访问者用于允许对象的子部分使用一致的方法来做某事。策略用于允许依赖注入如何做某事。
所以这将是一个访问者:
与另一个这种类型的
访问者我们有一个类,然后可以使用这个访问者来完成其工作,并根据它进行更改:
所以如果我们这样做
var person1 = new Person(new LightToucher());
var person2 = new Person(new HeavyToucher());
The defining difference is that the Visitor offers a different behavior for subclasses of the element, using operator overloading. It knows the sort of thing it is working upon, or visiting.
A Strategy, meanwhile, will hold a consistent interface across all its implementations.
A visitor is used to allow subparts of an object to use a consistent means of doing something. A strategy is used to allow dependency injection of how to do something.
So this would be a visitor:
with another one of this type
We have a class that can then use this visitor to do its work, and change based upon it:
So if we do this
var person1 = new Person(new LightToucher());
var person2 = new Person(new HeavyToucher());
我将策略模式视为将方法/策略注入对象的一种方式,但通常该方法的签名采用一些值参数并返回结果,因此它不与策略的用户耦合:
来自 Wikipedia :
访问者通过双重调度与用户耦合,并且通常保持状态。
很好的例子这里,我将从那里复制:
如您所见,访问者有状态(public int Count),并且它在已知类型 BlisterPack、Bottle、Jar 的列表上进行操作。因此,如果您想支持新类型,您需要通过添加该类型来更改所有访问者。
此外,由于“visitor.Visit(this);”,它与它所操作的类型耦合在一起。如果我删除或更改瓶子中的“物品”属性,会发生什么情况? ...所有访客都会失败。
I see strategy pattern as a way to inject a method/strategy into an object, but typically the signature of that method takes some value params and returns a result so it's not coupled with the user of the strategy:
From Wikipedia :
Visitor instead is coupled with the user through double dispatch and typically keeps state.
Good example here, I'll just copy from there:
As you can see the visitor has state(public int Count) and it operates on a list of know types BlisterPack, Bottle, Jar. So if you want to support a new type you need to change all visitors by adding that type.
Also it's coupled with the types it operates on because of "visitor.Visit(this);". What would happen if I remove or change the "Items" property form bottle? ... all visitors would fail.
如果我们查看 GoF 书中这两种模式的 UML,我们会发现它们毫无相似之处。
访客:
策略:
从图中可以看出一些重要的差异。
仅 UML 并不能捕获驱动这些模式的不同动机。
If we look at the UML for these two patterns from the GoF book, we see they are nothing alike.
Visitor:
Strategy:
Some important differences stand out from the diagrams.
UML alone does not capture the different motivations driving these patterns.
两者都是调度的方法(在运行时决定调用哪个函数)。区别在于你是支持算法(访问者)还是对象(策略):
因此,如果您有一个对象和多种算法 (1:n),那么策略就有意义,反之亦然,如果您有多个对象和只有一种算法,则最好使用访问者模式 (n:1)。
但是如果您有多个对象和多种算法怎么办?
在这种情况下,选择的算法将取决于另一个参数,对吧?因此,我们使用双重调度方法,该方法基于我们的对象和附加参数来选择算法。这通常也是通过重载解析来完成的,因此该模式将大部分类似于访问者模式 (n:n)。
过度简化*:
(*) 这种比较是在以下假设下进行的:begin() 方法根据 obj 中设置的当前策略改变其行为,而对于访问者,我们必须假设有不同的 begin () 重载浮动(但通常捆绑在一起在访问者对象中),并且根据我们放入其中的对象选择正确的重载。
Both are methods of dispatching (deciding at runtime which function to call). The difference lies in whether you side with the algorithm (visitor) or with the object (strategy):
Consequently, strategy makes sense if you have one object and multiple algorithms (1:n), vice versa if you have multiple objects and just one algorithm you're better off using the visitor patter (n:1).
But what if you have multiple objects and multiple algorithms?
In this case, the algorithm chosen would depend on another parameter, right? So we use a double dispatching method which bases the selection of the algorithm on our object and the additional parameter. This is also often done through overload resolution, so that pattern will resemble the visitor pattern mostly (n:n).
Oversimplified*:
(*) This comparison works under the assumption that the begin() method alters its behaviour based on the current strategy set in obj, whereas for the visitor we have to assume that there are different begin() overloads floating around (but usually bundled together in a visitor object) and the right one is picked based on the object we put into it.
对我来说,第二张图似乎是访问者模式...因为对于策略模式,包含数据结构的类往往只有一个,没有子类(或者子类保持这部分的相同行为)。该策略适用于同一结构上的不同操作。
Seems like the second graph is Visitor Pattern to me...Since for strategy pattern, the class contains data structure tends to be only one, no subclass(Or the subclass stays same behavior of this part). The strategy is for different operations on the same structure.
我会尝试做出最简短的答案。
这两种模式相互补充:例如,您可以使用访问者来更改图的所有节点上的策略。
I'll try to make the shortest answer.
The two patterns complement one another: for instance, you could use a visitor to change the strategies on all the nodes of a graph.
关键的不同之处之一是访问者模式允许您将不同的逻辑(访问者)插入现有的类(元素)中,只需对其进行最小的更改。它喜欢您公开一种机制,让其他人在您的类上运行逻辑,而无需更改实现你们班的。
One of the key different is the Visitor pattern allows you to plug in different logic (visitors) into an existing class (element) with minimal change to it.It likes you expose a mechanism other people to run logic on your class without changing the implementation of your class.
它们的区别是:
不确定比较两个不同的事物会得到什么,但比较策略 至访客。
两者有什么相同之处,让人去寻找他们的不同之处呢?
Their differences are :
Not sure what is gained from comparing two different things but compare Strategy to Visitor.
What is same about the two to make one look for their differences?