Visitor pattern and double-Dispatch

Source: Internet
Author: User
Override vs. Overload

Simple polymorphism (override): the object whose method is called is decided run-time.
Multi-polymorphism (overload): the object which method is called is decided upon the type
The argument.

Upcast is implicit. The upward transformation is implicit, and downcast is displayed.

That is to say, when you say that a square is a shape, it is okay. But when you say the shape is square, you must display the square shapea

If the shape is circular, it will be crash at runtime, and give you java. Lang. classcastexception

Let's look at an example:

Public class coloredhorses {public void display (horse H) {system. out. println ("horse:" + H. message ();} // which message method is called. It depends on the runtime object's public void display (Whitehorse Wh) {system. out. println ("Whitehorse:" + Wh. message ();} public void display (Blackhorse BH) {system. out. println ("Blackhorse:" + bH. message ();} public static void main (string [] ARGs) {coloredhorses test = new coloredhorses (); horse H1 = new whi Tehorse (); // H1 is declared as horse, but points to the Whitehorse object horse H2 = new Blackhorse (); Whitehorse wh = new Whitehorse (); Blackhorse bH = new Blackhorse (); test. display (H1); // which display method is called? Because type is horse, it is display (horse H) test. display (H2); // if there is no display (Horse), a compilation error will be reported unless you display the transformation to a subclass such as (Blackhorse) h2test. display (Wh); // No compilation error even if there is no display (Whitehorse), because the upcast can be implicitly written to horse, and then the display (Horse) test is called. display (BH) ;}} class horse {protected string message () {return "I am a horse" ;};}; class Whitehorse extends horse {protected string message () {return "I am a white horse" ;};}; class Blackhorse extends horse {protected string message () {return "I am a black horse ";};};

What is its output?

Horse:I am a white horseHorse:I am a black horseWhiteHorse:I am a white horseBlackHorse:I am a black horse

Visitor pattern

Visitor mode, as the name implies, with this mode, you can add additional "visitors" without modifying the existing program structure to improve the existing code functions.

The design pattern book defines the visitor pattern as an operation that acts on each element of an object structure. It allows you to define new operations that act on these elements without changing the classes of each element. From the definition, we can see that the structure object is a required condition for using the visitor mode, and this structure object must have a method to traverse its own objects. This is similar to the Collection concept in Java.

The structure of the visitor mode is as follows:

1) Visitor role (visitor): declares an access operation interface for the specific element role in the object structure. The name and parameters of this operation interface identify the specific element role that sends an access request to a specific visitor. In this way, the visitor can directly access the element through a specific interface of the element role.

2) A specific visitor role (concrete visitor): implements each operation declared by the visitor role (visitor.

3) element: defines an accept operation, which takes a visitor as the parameter.

4) specific element (concrete element): implements the accept operation provided by the element role.

5) object structure Role: This is a required role in the visitor mode. It must have the following features: it can enumerate its elements; it can provide a high-level interface to allow the visitor to access its elements; it can be a combination (combination mode) or a set, such as a list or an unordered set.

For example:

Import Java. util. arraylist; import Java. util. list; public class vistorpattern {public static void main (string [] ARGs) {flowerscompo flowers = new flowerscompo (); flowers. addflower (New gladiolus (); flowers. addflower (New runuculus (); flowers. accept (New beevisitor () ;}// visitor role interface visitor {void visit (gladiolus g); void visit (runuculus R); void visit (Chrysanthemum C );} // The flower Hierarchy cannot be changed: // element role interface flower {void accept (visitor V );} // The following three specific element roles: Class gladiolus implements flower {public void accept (visitor v) {v. visit (this) ;}} class runuculus implements flower {public void accept (visitor v) {v. visit (this) ;}} class chrysanthemum implements flower {public void accept (visitor v) {v. visit (this) ;}}// object structure Role (object structure) Class flowerscompo {list <flower> flowers = new arraylist <flower> (); Public void addflower (flower f) {flowers. add (f);} public void removeflower (flower f) {flowers. remove (f);} public void accept (visitor v) {for (flower f: Flowers) {f. accept (v) ;}}// Add the ability to produce a string: // The specific visitor role class strvisitor implements visitor {string s; Public String tostring () {return s;} public void visit (gladiolus g) {S = "gladiolus";} public void visit (runuculus R) {S = "runuculus ";} public void visit (Chrysanthemum c) {S = "Chrysanthemum" ;}// Add the ability to do "Bee" activities: // another specific visitor role class beevisitor implements visitor {public void visit (gladiolus g) {system. out. println ("Bee and gladiolus");} public void visit (runuculus R) {system. out. println ("Bee and runuculus");} public void visit (Chrysanthemum c) {system. out. println ("Bee and Chrysanthemum ");}}

A typical use of visitor is that there is a set of data that requires different forms of presentation. In this way, when the object structure changes, we only need to change the object structure object, increase or decrease the element in it.

When you need a new display form, you only need to implement a new visitor.

Because the components that are easy to change (object structure and presentation form) are encapsulated and decoupled, and can be expanded independently, the entire design is relatively flexible.

You do not need to use accept (). You can use visitor to directly access the visit () Element Object?

Of course it is okay, and this saves the element dependency on visitor and further reduces coupling. We will try to change the above program to an Accept-free one.

Modify the object structure as follows:

Class flowerscompo {list <flower> flowers = new arraylist <flower> (); Public void addflower (flower f) {flowers. add (f);} public void removeflower (flower f) {flowers. remove (f);} public void accept (visitor v) {for (flower f: Flowers) {// F. accept (V); V. visit (f); // use visitor to directly access the element. The Compiler reports an error }}}

After the program is changed, the compiler reports an error prompting that the visit (flower) method is not defined. Based on the override and overload described above, in overload, which method is called is statically bound during compilation. For details, although we have defined visit (gladiolus g), visit (runuculus R), visit (Chrysanthemum
C) but no visit (flower) method is defined

Then define it in visitor:

Interface visitor {void visit (flower f); // added void visit (gladiolus g); void visit (runuculus R ); void visit (Chrysanthemum C );}

The interface has changed, so every concretevisitor must implement this visit (flower). In order to distinguish the real object in the runtime time zone, the beevisitor statement is as follows:

Class beevisitor implements visitor {public void visit (flower f) {// determine the runtime object through instanceof and call the specific method of overload if (F instanceof gladiolus) {visit (gladiolus) F);} else if (F instanceof runuculus) {visit (runuculus) F);} else if (F instanceof chrysanthemum) {visit) f) ;}} public void visit (gladiolus g) {system. out. println ("Bee and gladiolus");} public void visit (runuculus R) {system. out. println ("Bee and runuculus");} public void visit (Chrysanthemum c) {system. out. println ("Bee and Chrysanthemum ");}}

If this is done, every visitor implementation needs to rewrite the same visit (flower) code, make a change, and put visit (flower) in an abstract method. below is the visitor after the accept is removed.

Import Java. util. arraylist; import Java. util. list; public class vistorpattern {public static void main (string [] ARGs) {flowerscompo flowers = new flowerscompo (); flowers. addflower (New gladiolus (); flowers. addflower (New runuculus (); flowers. accept (New beevisitor () ;}// visitor role interface visitor {public void visit (flower f); Public void visit (gladiolus G ); public void visit (runuculus R); Public void visit (Chrysanthemum C);} abstract class implements actvisitor implements visitor {public void visit (flower f) {If (F instanceof gladiolus) {visit (gladiolus) F);} else if (F instanceof runuculus) {visit (runuculus) F);} else if (F instanceof chrysanthemum) {visit) f) ;}}// the flower Hierarchy cannot be changed: // element role interface flower {}// the following three specific element roles: Class gladiolus implements flower {} class runuculus implements flower {} class chrysanthemum implements flower {}// object structure Role (object structure) class flowerscompo {list <flower> flowers = new arraylist <flower> (); Public void addflower (flower f) {flowers. add (f);} public void removeflower (flower f) {flowers. remove (f);} public void accept (visitor v) {for (flower f: Flowers) {// F. accept (V); V. visit (f) ;}}// Add the ability to produce a string: // The specific visitor role class strvisitor extends actvisitor {string s; Public String tostring () {return s;} public void visit (gladiolus g) {S = "gladiolus";} public void visit (runuculus R) {S = "runuculus ";} public void visit (Chrysanthemum c) {S = "Chrysanthemum" ;}// Add the ability to do "Bee" activities: // another specific visitor role class beevisitor extends actvisitor {public void visit (gladiolus g) {system. out. println ("Bee and gladiolus");} public void visit (runuculus R) {system. out. println ("Bee and runuculus");} public void visit (Chrysanthemum c) {system. out. println ("Bee and Chrysanthemum ");}}

Let's look back at why accept () is used in the Orthodox visitor mode. In fact, this is a double-Dispatch mode. Let's take a closer look at the accept Implementation of concreteelement.

Class chrysanthemum implements flower {public void accept (visitor v) {v. Visit (this); // visit (this) solves the visit (flower) problem }}

Since you cannot decide which visit () method to call at runtime, I will invite you in and then let you call me again, in fact, it solves the problem that we must use instanceof to differentiate.

In my opinion, to avoid using accept () is a visitor mode, the key is to understand its meaning and applicable scenarios.

Its core is some basic object-oriented design principles: encapsulation and change principles, open-close principles, and so on.

Note:

When using visitor, the structure of the visit class should be as stable as possible, because the addition of a new visit object means that you want to modify the visit interface and all the concretevisitor.

It is also a good choice to assemble objects that need to be visit in combination mode.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.