53

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.

enter image description here

enter image description here

3

12 Answers 12

120

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:

MpegCompression
AviCompression
QuickTimeCompression

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:

MpegVideoCompression
MpegAudioCompression

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:

MpegCompressionVisitor::compressVideo(Video object)    
MpegCompressionVisitor::compressAudio(Audio object)

[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.

// Visitor interface
interface Compressor {

  // Visitor methods
  void compress(Video object);
  void compress(Audio object);
}

// Visitor implementation
class MpegCompressor implements Compressor {
  
  public void compress(Video object) {
    // ...
  }

  public void compress(Audio object) {
    // ...
  }
}

And now the interface and class to be visited:

interface Compressible {

  void accept(Compressor compressor);
}

class Video implements Compressible {

  // If the Compressor is an instance of MpegCompressionVisitor,
  // the system prints "Mpeg video compression"
  void accept(Compressor compressor) {
    compressor.compress(this);
}
3
  • 5
    You can also use bridge to avoid MpegVideo /MpegAudio Commented Oct 2, 2013 at 7:47
  • @ahoffer So, compressVideo and compressAudio are my two visit function. and Video class will visit compressVideo and Audio class will visit compressAudio . Am I understanding it right?
    – EmptyData
    Commented Nov 19, 2016 at 15:04
  • @EmptyData Yes. The compress methods would be your visitor methods. I would describe the MpegCompression class as the visitor. The Video objects are visited.
    – ahoffer
    Commented Nov 22, 2016 at 17:09
16

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?

3
  • I just added two image. That i implemented for understanding. Can you give idea in that context.
    – dotnetstep
    Commented Dec 29, 2011 at 8:47
  • 1
    Two sides of the same coin +1
    – medunes
    Commented Mar 15, 2021 at 0:25
  • Far from two sides of the same coin. Strategy and Visitor are unrelated.
    – jaco0646
    Commented Feb 11, 2022 at 22:52
15

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:

package DesignPatterns;

public class CarGarageStrategyDemo 
{
    public static interface RepairStrategy
    {
        public void repair(Car car);
    }

    public static interface Car
    {
        public String getName();
        public void repair(RepairStrategy repairStrategy);
    }

    public static class PorscheRepairStrategy implements RepairStrategy
    {
        @Override
        public void repair(Car car) {
            System.out.println("Repairing " + car.getName() + " with the Porsche repair strategy");
        }
    }
    
    public static class FerrariRepairStrategy implements RepairStrategy
    {
        @Override
        public void repair(Car car) {
            System.out.println("Repairing " + car.getName() + " with the Ferrari repair strategy");
        }
    }

    public static class Porsche implements Car
    {
        public String getName()
        {
            return "Porsche";
        }

        @Override
        public void repair(RepairStrategy repairStrategy) {
            repairStrategy.repair(this);
        }
    }

    public static void main(String[] args)
    {
        Car porsche = new Porsche();
        porsche.repair(new PorscheRepairStrategy()); //Repairing Porsche with the porsche repair strategy
    }
}

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:

...
    public static void main(String[] args)
    {
        Car porsche = new Porsche();
        porsche.repair(new FerrariRepairStrategy()); //We cannot repair a Porsche as a Ferrari!
    }
...

So in this case we can use the visitor pattern.

Visitor

The problem

Consider the code below:

public class CarGarageVisitorProblem
{
    public static interface Car
    {
        public String getName();
    }

    public static class Porsche implements Car
    {
        public String getName()
        {
            return "Porsche";
        }
    }

    public static class Ferrari implements Car
    {
        public String getName()
        {
            return "Ferrari";
        }
    }

    public void repair(Car car)
    {
        System.out.println("Applying a very generic and abstract repair");
    }

    public void repair(Porsche car)
    {
        System.out.println("Applying a very specific Porsche repair");
    }

    public void repair(Ferrari car)
    {
        System.out.println("Applying a very specific Ferrari repair");
    }

    public static void main(String[] args)
    {
        CarGarageVisitorProblem garage = new CarGarageVisitorProblem();
        Porsche porsche = new Porsche();
        garage.repair(porsche); //Applying a very specific Porsche repair
    }
}

The output is Applying a very specific Porsche repair. The problem is that this line is not abstract, but concrete:

Porsche porsche = new Porsche();

We want to write it as (or inject an instance of Car in the constructor, we want to apply the Dependency Inversion Principle):

Car porsche = new Porsche();

But when we change this line, the output will be:

Applying a very generic and abstract repair

Not what we want!

The solution; using double dispatch (and the Visitor pattern)

package DesignPatterns;

public class CarGarageVisitorExample 
{
    public static interface Car
    {
        public String getName();
        public void repair(RepairVisitorInterface repairVisitor);
    }

    public static class Porsche implements Car
    {
        public String getName()
        {
            return "Porsche";
        }

        public void repair(RepairVisitorInterface repairVisitor)
        {
            repairVisitor.repair(this);
        }
    }

    public static class Ferrari implements Car
    {
        public String getName()
        {
            return "Ferrari";
        }

        public void repair(RepairVisitorInterface repairVisitor)
        {
            repairVisitor.repair(this);
        }
    }

    public static interface RepairVisitorInterface
    {
        public void repair(Car car);
        public void repair(Porsche car);
        public void repair(Ferrari car);
    }

    public static class RepairVisitor implements RepairVisitorInterface
    {
        public void repair(Car car)
        {
            System.out.println("Applying a very generic and abstract repair");
        }

        public void repair(Porsche car)
        {
            System.out.println("Applying a very specific Porsche repair");
        }

        public void repair(Ferrari car)
        {
            System.out.println("Applying a very specific Ferrari repair");
        }
    }

    public static void main(String[] args)
    {
        CarGarageVisitor garage = new CarGarageVisitor();
        Car porsche = new Porsche();
        porsche.repair(new RepairVisitor()); //Applying a very specific Porsche repair
    }
}

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:

public void repair(RepairVisitorInterface repairVisitor)
{
    repairVisitor.repair(this);
}

The this reference will return the concrete type of the object, not the abstract (Car) type.

3
  • The Strategy Pattern is implemented via composition, which is not shown in this example.
    – jaco0646
    Commented Sep 2, 2020 at 2:45
  • 1
    Yes, strictly speaking. With composition you cannot vary the strategy/ visitor without creating a new subject. On the other side, composition can also be used with the visitor pattern. The question is, which situation serves you best. Car porsche = new Porsche(new CarGarageVisitor()); porsche.repair();
    – Solonl
    Commented Sep 7, 2020 at 21:18
  • The strategy can vary by setting a new one on the context. Composition is not used with the Visitor pattern. I have added the GoF UML in an answer below. The root of the problem in the OP is that its UML is incorrect; so the question is based on faulty premises.
    – jaco0646
    Commented Sep 8, 2020 at 14:51
12

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 :)

1
  • I see it the same way. A strategy is something an Object requires to fulfill his duties right from the start. And a Visitor is something optional which can pass by but doesn't have to
    – velop
    Commented Aug 13, 2019 at 9:21
3

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:

class LightToucher : IToucher{
    string Touch(Head head){return "touched my head";}
    string Touch(Stomach stomach){return "hehehe!";}
}

with another one of this type

class HeavyToucher : IToucher{
   string Touch(Head head){return "I'm knocked out!";}
   string Touch(Stomach stomach){return "oooof you bastard!";}
}

We have a class that can then use this visitor to do its work, and change based upon it:

class Person{
    IToucher visitor;
    Head head;
    Stomach stomach;
    public Person(IToucher toucher)
    {
          visitor = toucher;

          //assume we have head and stomach
    }

    public string Touch(bool aboveWaist)
    {
         if(aboveWaist)
         {
             visitor.Touch(head);
         }
         else
         {
             visitor.Touch(stomach);
         }
    }
}

So if we do this var person1 = new Person(new LightToucher()); var person2 = new Person(new HeavyToucher());

        person1.Touch(true); //touched my head
        person2.Touch(true);  //knocked me out!
2

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 :

class Minus : ICalculateStrategy {
    public int Calculate(int value1, int value2) {
        return value1 - value2;
    }
}

Visitor instead is coupled with the user through double dispatch and typically keeps state. Good example here, I'll just copy from there:

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; }
}

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
}

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

    #region IAcceptor Members

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

    #endregion
}

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.

2

If we look at the UML for these two patterns from the GoF book, we see they are nothing alike.

Visitor:

Visitor UML


Strategy:

Strategy UML


Some important differences stand out from the diagrams.

  • Strategy is based on composition. Visitor has no composition relationship.
  • Strategy is based on coding to an interface. Visitor is based on coding to an implementation.
  • Strategy implements one operation in multiple ways. Visitor implements multiple operations.

UML alone does not capture the different motivations driving these patterns.

  • Strategy is an object-oriented solution for languages without first-class functions. As modern languages adopt closures or lambdas, there is less need for the Strategy Pattern.
  • Visitor is an object-oriented solution for languages without pattern matching or multiple dispatch. As modern languages adopt these features, Visitor too becomes obsolete.
2

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):

  • With the strategy pattern we inject a strategy (object / functor / lambda) in our main object, and every time a specific method is called we delegate that call to the currently active strategy to execute.
  • With a visitor pattern we don't delegate from the object but instead we throw our object at a so called Visitor object/function, which based on this parameter chooses (usually through overload resolution) the algorithm it wants to apply to our passed object.

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*:

begin(obj); // <-- visitor
obj.begin(); // <-- strategy

(*) 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.

0

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.

0

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.

0

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.

-6

Their differences are :

  1. Motivation
  2. Intent
  3. Implementation

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?

6
  • 1
    This is more of a long comment than an answer to the question.
    – Oded
    Commented Dec 29, 2011 at 8:27
  • @Oded : Edited the response, but how sensible is it to ask for differences between a watermelon and an airplane? :)
    – jimjim
    Commented Dec 29, 2011 at 8:30
  • 2
    The OP does not understand what they are. I would expect an answer to explain each pattern and give context and possibly examples. See the answer from @Francois.
    – Oded
    Commented Dec 29, 2011 at 8:35
  • @Oded : Aha, now I understand why. tx
    – jimjim
    Commented Dec 29, 2011 at 8:39
  • 1
    They are similar in that they're both patterns dealing with the abstraction of execution. So it's grapefruit and oranges, not apples and oranges.
    – Mathieson
    Commented Nov 13, 2013 at 21:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.