definition: encapsulates operations that act on elements of a data structure, and it can define new operations that function on these elements without altering the data structure.
Type: behavior class pattern
class Diagram:
Example:
For example, consider a shopping cart that adds different types of merchandise, and when clicked, it calculates the cost of all the different items. Now, the computational logic is to calculate the price of these different types of goods. Or, through the visitor pattern, we move this logic to another class. Let's implement an example of this visitor pattern.
To implement the visitor pattern, the first thing to do is to create classes that can be added to the shopping cart to represent different types of goods (itemelement).
Itemelement.java
package com.journaldev.design.visitor;
Public interface Itemelement {public
int accept (Shoppingcartvisitor visitor);
}
Note that the Accept method accepts accessors as parameters. Of course there are other ways to specify detailed products, but in order to simplify, there is no way to consider the details and focus only on the visitor pattern.
Now create the entity classes for some different items.
Book.java
Package com.journaldev.design.visitor;
public class Book implements itemelement {
private int price;
Private String Isbnnumber;
public book (int cost, String ISBN) {
this.price=cost;
THIS.ISBNNUMBER=ISBN;
}
public int GetPrice () {return price
;
}
Public String Getisbnnumber () {return
isbnnumber;
}
@Override public
int Accept (Shoppingcartvisitor visitor) {return
visitor.visit (this);
}
}
Fruit.java
Package com.journaldev.design.visitor;
public class Fruit implements itemelement {
private int priceperkg;
private int weight;
private String name;
Public Fruit (int pricekg, int wt, String nm) {
this.priceperkg=pricekg;
THIS.WEIGHT=WT;
THIS.name = NM;
}
public int getpriceperkg () {return
priceperkg;
}
public int getweight () {return
weight;
}
Public String GetName () {return
this.name;
}
@Override public
int Accept (Shoppingcartvisitor visitor) {return
visitor.visit (this);
}
}
Note that the implementation of the Accept () method is in the entity class, which invokes the accessor's visit () method to pass the current class object as its own argument.
The visit () method used here for different types of goods will be implemented in the entity class of the visitor interface.
Shoppingcartvisitor.java
Package com.journaldev.design.visitor;
Public interface Shoppingcartvisitor {
int visit (book book);
int visit (Fruit Fruit);
}
Now it's time to implement the visitor interface and the logic for each item to calculate its own cost.
Shoppingcartvisitorimpl.java
Package com.journaldev.design.visitor;
public class Shoppingcartvisitorimpl implements Shoppingcartvisitor {
@Override public
int visit C4/>int cost=0;
Apply 5$ discount If book price is greater than
if (Book.getprice () > x) {Cost
= Book.getprice ()-5;
} else cost = Book.getprice ();
System.out.println ("Book ISBN::" +book.getisbnnumber () + "cost =" +cost);
return cost;
}
@Override Public
int visit (Fruit Fruit) {
int cost = FRUIT.GETPRICEPERKG () *fruit.getweight ();
System.out.println (Fruit.getname () + "cost =" +cost);
return cost;
}
Now look at how you can use it in your program.
Shoppingcartclient.java
Package com.journaldev.design.visitor;
public class Shoppingcartclient {public
static void Main (string[] args) {
itemelement[] items = new itemelement[] {new book (' 1234 '), new book (+, "5678"), New
Fruit (2, "Banana"), New Fruit (5, 5, "Apple")};
int total = Calculateprice (items);
SYSTEM.OUT.PRINTLN ("Total cost =" +total);
}
private static int Calculateprice (itemelement[] items) {
Shoppingcartvisitor visitor = new Shoppingcartvisitorimpl ( );
int sum=0;
for (Itemelement item:items) {
sum = sum + item.accept (visitor);
}
return sum;
}
When the above program is run, we get the following output.
Book isbn::1234 $ =20 book
isbn::5678 $ =95 Banana cost = Apple cost =
160
Note that the implementation here, as if the Accept () method is the same for all products, but he can also be different. For example, if the product is empty it can perform a logical check and no longer invoke the visit () method.
Advantages of the visitor pattern:
Consistent with the principle of single responsibility: In any scenario where the visitor pattern is applied, an action that needs to be encapsulated in a visitor in an element class must be an operation that is not related to the element class itself and is variable, and the visitor pattern conforms to a single responsibility principle, on the other hand, because the encapsulated operation is usually variable, so when a change occurs , you can extend the change section without changing the element class itself.
Extensibility is good: the element class can extend to different operations by accepting different audiences.
application Scenarios for visitor patterns:
If there are operations in an object that are irrelevant (or relatively weak) to this object, you can use the visitor pattern to encapsulate these operations to the visitor in order to avoid polluting the object.
If there are similar operations in a group of objects, they can be encapsulated into the visitor to avoid a large number of duplicated code.
However, the visitor pattern is not perfect, and it has a fatal flaw: Adding new element classes is more difficult. You can see from the visitor pattern's code that in the visitor class, each element class has its corresponding processing method, that is to say, each additional element class needs to modify the visitor Class (also includes the visitor class subclass or the implementation Class), the modification is quite troublesome. That is, in the case of an indeterminate number of element classes, the visitor pattern should be used with caution. So, the visitor pattern is more suitable for refactoring the existing functionality, for example, the basic function of a project has been determined, the element class data has been basically determined not to change, will change only the relevant operations within these elements, at this time, we can use the visitor pattern to refactor the original code, so that, You can modify the original functionality without modifying the individual element classes.
Summary:
as the author of design mode Gof a description of the visitor pattern: In most cases, you need to use the visitor pattern, but when you need to use it, you really need it. Of course, this is only for the real Daniel. In the real world (at least in my environment), many people tend to indulge in design patterns, and when they use a design pattern, they never seriously consider whether the pattern is appropriate for the scenario, and often just want to show their mastery of object-oriented design. When programming with this kind of psychology, often can take place misuse design pattern of circumstance. Therefore, in learning design patterns, we must understand the applicability of the model. It is necessary to use a pattern because understanding its advantages, not using a pattern because of understanding its drawbacks, rather than using a pattern because you do not understand its drawbacks, do not use a pattern because you do not understand its advantages.