I have learned both the patterns but did not understand the differences between these two patterns.
I do not know scenarios, when and where to use these patterns.
Can any one explain the differences and use cases?
I have learned both the patterns but did not understand the differences between these two patterns.
I do not know scenarios, when and where to use these patterns.
Can any one explain the differences and use cases?
The main difference is that the Strategy Pattern encapsulates a single group of related behaviors, while the Visitor Pattern encapsulates multiple such groups.
Visitor pattern intent:
Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
Use Visitor pattern if:
Even though Visitor pattern provides flexibility to add new operation without changing the existing code in Object, this flexibility has come with a drawback.
If a new Visitable object has been added, it requires code changes in Visitor & ConcreteVisitor classes. There is a workaround to address this issue : Use reflection, which will have impact on performance.
Refer to oodesign article and sourcemaking articles for more details
Strategy pattern intent:
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.
Strategy lets you change the guts of an object.
Refer to below SE questions for more details:
Visitor pattern is used to traverse the object hierarchy and provide some functionality like printing or reporting etc., I used this to provide different formats (Text/HTML) to print an object hierarchy by writing multiple visitors, one for each format. The objects in the hierarchy are the visitables.
Strategy pattern is used to pick a particular logical path based on the input. A classic example is authentication filters where based on the value in the Authorization
HTTP header, different authentication strategies like NTLM/Negotiate/Basic are picked and run. The filter would hold a reference to the AuthenticationStrategy interface, based on the incoming request, a particular authentication strategy is picked and assigned to this reference and the code that follows doesn't need to know the exact strategy being used.
Visitor is for when you have a family of classes and you need to add new functionality to every class in that family but not touch the classes themselves (or wish to have that new functionality all defined in one place - the visitor)
Strategy is for when you have a family of classes that need to be able to do something in order to work properly (such as sort some objects they contain) but you want the client or your dependancy injection to tell them which way to go about doing that.
In addition to the behavioural difference mentioned above, I also experienced a difference regarding the dependencies and use cases during a project once I was working on, like the following.
For example, Visitor knows about concrete classes. So you will be more flexible at the expense of changing your visitor code as you add new concrete classes to the hierarchy. There's no such thing in Strategy. In this context, Strategy becomes more suitable if you've methods only to return some output with a given input, regardless of the context.
Moreover, Visitor pattern also used to implement SRP of SOLID, to separate concerns.
Imagine you are building a cash register app that's building receipts. And let's say you want to:
1. ensure that different kind of items (books, fruit, meat, toiletries etc) are being processed differently
2. keep the logic of actual calculation of the price separately from the item definitions
3. ensure that if the shop starts selling something completely new (let's say cloth that will be charged by length), you won't have to change too many codes
Visitor could be a class that defines different kinds of calculations depending on what kind of item is being processed. It's a service that moves away the differences in price calculations away from the hierarchy of items.
where the body of getPrice
could look like this:
getPrice(Calculation c) {
return c.calculate(this); // <-- visitor.visit( specific implementation )
}
and in say ShoppingCart
you will do:
calc = getPriceCalculator()
foreach item in items:
totalPrice += item.getPrice(calc)
Imagine this scenario: On Black Friday you want to do some crazy discounts, 70% off of all books, 50% off of all fruit. You can easily do something along the lines:
BlackFridayCalculator extends PriceCalculator {
calculate(Book b) { return 0.3 * parent.calculate(b) }
calculate(Fruit f) { return 0.5 * parent.calculate(f) }
}
// and in getPriceCalculator:
return (black friday time) ? new BlackFridayCalculator() : new PriceCalculator();
Strategy instead could have a hierarchy of a different kind of calculations (strategies) and each item would then define, which calculation (strategy) should be used ("plugged").
Now there are many ways how to define which item should use which calculation. The most straightforward would be giving Item
method getCalculator
and let each item choose which calculation it needs.
This might be a bit less dynamic - in a sense that each item needs to have a predefined calculator that will be used. But think of this scenario: Owner of the shop decides that pineapples and watermelons should be sold per piece - we can easily let Fruit
use WeightCalculator
by default and create a subset of fruit that will be sold by quantity.