我什么时候应该使用访客设计模式? [关闭]

本文翻译自:When should I use the Visitor Design Pattern? [closed]

I keep seeing references to the visitor pattern in blogs but I've got to admit, I just don't get it. 我一直在博客中看到对访客模式的引用,但我必须承认,我只是不明白。 I read the wikipedia article for the pattern and I understand its mechanics but I'm still confused as to when I'd use it. 我阅读了维基百科文章的模式 ,我理解它的机制,但我仍然对我何时使用它感到困惑。

As someone who just recently really got the decorator pattern and is now seeing uses for it absolutely everywhere I'd like to be able to really understand intuitively this seemingly handy pattern as well. 作为最近刚刚获得装饰模式的人,现在看到它在任何地方的用途我都希望能够直观地理解这个看似方便的模式。


#1楼

参考:https://stackoom.com/question/14OM/我什么时候应该使用访客设计模式-关闭


#2楼

In my opinion, the amount of work to add a new operation is more or less the same using Visitor Pattern or direct modification of each element structure. 在我看来,使用Visitor Pattern或直接修改每个元素结构,添加新操作的工作量大致相同。 Also, if I were to add new element class, say Cow , the Operation interface will be affected and this propagates to all existing class of elements, therefore requiring recompilation of all element classes. 另外,如果我要添加新的元素类,比如说Cow ,那么Operation接口将受到影响,并且会传播到所有现有的元素类,因此需要重新编译所有元素类。 So what is the point? 那有什么意义呢?


#3楼

Visitor Pattern as the same underground implementation to Aspect Object programming.. Visitor Pattern作为Aspect对象编程的相同地下实现..

For example if you define a new operation without changing the classes of the elements on which it operates 例如,如果您定义新操作而不更改其操作的元素的类


#4楼

There are at least three very good reasons for using the Visitor Pattern: 使用访客模式至少有三个非常好的理由:

  1. Reduce proliferation of code which is only slightly different when data structures change. 减少代码的扩散,这在数据结构发生变化时略有不同。

  2. Apply the same computation to several data structures, without changing the code which implements the computation. 将相同的计算应用于多个数据结构,而不更改实现计算的代码。

  3. Add information to legacy libraries without changing the legacy code. 在不更改旧代码的情况下将信息添加到旧库。

Please have a look at an article I've written about this . 请看一篇我写的关于此的文章


#5楼

While I have understood the how and when, I have never understood the why. 虽然我已经理解了如何以及何时,但我从未理解为什么。 In case it helps anyone with a background in a language like C++, you want to read this very carefully. 如果它能帮助任何具有C ++语言背景的人,你想要仔细阅读

For the lazy, we use the visitor pattern because "while virtual functions are dispatched dynamically in C++, function overloading is done statically" . 对于懒惰,我们使用访问者模式,因为“当在C ++中动态调度虚函数时,函数重载是静态完成的”

Or, put another way, to make sure that CollideWith(ApolloSpacecraft&) is called when you pass in a SpaceShip reference that is actually bound to an ApolloSpacecraft object. 或者,换句话说,确保在传入实际绑定到ApolloSpacecraft对象的SpaceShip引用时调用CollideWith(ApolloSpacecraft&)。

class SpaceShip {};
class ApolloSpacecraft : public SpaceShip {};
class ExplodingAsteroid : public Asteroid {
public:
  virtual void CollideWith(SpaceShip&) {
    cout << "ExplodingAsteroid hit a SpaceShip" << endl;
  }
  virtual void CollideWith(ApolloSpacecraft&) {
    cout << "ExplodingAsteroid hit an ApolloSpacecraft" << endl;
  }
}

#6楼

I found it easier in following links: 我发现以下链接更容易:

In http://www.remondo.net/visitor-pattern-example-csharp/ I found an example that shows an mock example that shows what is benefit of visitor pattern. http://www.remondo.net/visitor-pattern-example-csharp/中,我找到了一个示例,其中显示了一个模拟示例,显示了访问者模式的好处。 Here you have different container classes for Pill : 这里你有不同的Pill容器类:

namespace DesignPatterns
{
    public class BlisterPack
    {
        // Pairs so x2
        public int TabletPairs { get; set; }
    }

    public class Bottle
    {
        // Unsigned
        public uint Items { get; set; }
    }

    public class Jar
    {
        // Signed
        public int Pieces { get; set; }
    }
}

As you see in above, You BilsterPack contain pairs of Pills' so you need to multiply number of pair's by 2. Also you may notice that Bottle use unit which is different datatype and need to be cast. 正如您在上面看到的,You BilsterPack包含成对的Pills'因此您需要BilsterPack数量乘以2.此外,您可能会注意到Bottle使用的unit是不同的数据类型,需要进行投射。

So in main method you may calculate pill count using following code: 因此,在主要方法中,您可以使用以下代码计算药丸计数:

foreach (var item in packageList)
{
    if (item.GetType() == typeof (BlisterPack))
    {
        pillCount += ((BlisterPack) item).TabletPairs * 2;
    }
    else if (item.GetType() == typeof (Bottle))
    {
        pillCount += (int) ((Bottle) item).Items;
    }
    else if (item.GetType() == typeof (Jar))
    {
        pillCount += ((Jar) item).Pieces;
    }
}

Notice that above code violate Single Responsibility Principle . 请注意,上述代码违反了Single Responsibility Principle That means you must change main method code if you add new type of container. 这意味着如果添加新类型的容器,则必须更改主方法代码。 Also making switch longer is bad practice. 使开关更长是不好的做法。

So by introducing following code: 因此,通过引入以下代码:

public class PillCountVisitor : IVisitor
{
    public int Count { get; private set; }

    #region IVisitor Members

    public void Visit(BlisterPack blisterPack)
    {
        Count += blisterPack.TabletPairs * 2;
    }

    public void Visit(Bottle bottle)
    {
        Count += (int)bottle.Items;
    }

    public void Visit(Jar jar)
    {
        Count += jar.Pieces;
    }

    #endregion
}

You moved responsibility of counting number of Pill s to class called PillCountVisitor (And we removed switch case statement). 您将计数Pill的数量的责任转移到了名为PillCountVisitor类(并且我们删除了switch case语句)。 That mean's whenever you need to add new type of pill container you should change only PillCountVisitor class. 这意味着每当你需要添加新类型的药丸容器时,你应该只改变PillCountVisitor类。 Also notice IVisitor interface is general for using in another scenarios. 另请注意, IVisitor接口通常用于其他方案。

By adding Accept method to pill container class: 通过将Accept方法添加到药丸容器类:

public class BlisterPack : IAcceptor
{
    public int TabletPairs { get; set; }

    #region IAcceptor Members

    public void Accept(IVisitor visitor)
    {
        visitor.Visit(this);
    }

    #endregion
}

we allow visitor to visit pill container classes. 我们允许访客参观药丸容器类。

At the end we calculate pill count using following code: 最后,我们使用以下代码计算药丸计数:

var visitor = new PillCountVisitor();

foreach (IAcceptor item in packageList)
{
    item.Accept(visitor);
}

That mean's: Every pill container allow the PillCountVisitor visitor to see their pills count. 这意味着:每个药丸容器都允许PillCountVisitor访客看到他们的药丸数量。 He know how to count your pill's. 他知道如何计算你的药丸。

At the visitor.Count has the value of pills. visitor.Count具有丸的价值。

In http://butunclebob.com/ArticleS.UncleBob.IuseVisitor you see real scenario in which you can not use polymorphism (the answer) to follow Single Responsibility Principle. http://butunclebob.com/ArticleS.UncleBob.IuseVisitor中,您会看到不能使用多态 (答案)遵循单一责任原则的真实场景。 In fact in: 事实上在:

public class HourlyEmployee extends Employee {
  public String reportQtdHoursAndPay() {
    //generate the line for this hourly employee
  }
}

the reportQtdHoursAndPay method is for reporting and representation and this violate the Single Responsibility Principle. reportQtdHoursAndPay方法用于报告和表示,这违反了单一责任原则。 So it is better to use visitor pattern to overcome the problem. 所以最好使用访问者模式来克服这个问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值