The Coffee Machine

Java & Eclipse tips blog

  • Categories

  • Archives

  • August 2008
    M T W T F S S
        Sep »
     123
    45678910
    11121314151617
    18192021222324
    25262728293031
  • Advertisements

The Visitor Pattern

Posted by ObLiB on August 25, 2008

Design PatternsFor my work I needed to browse a “tree” to retrieve some data and make operations with it. To manage this, I made some research and I found a design pattern that I didn’t know yet: The Visitor Pattern.

To spread a hierarchy of classes, normally you simply add methods which provide desired behavior. It can happen however that this behavior is not consistent with the logic of the existent object model. It is also possible that you do not have access to existent code. In such situations, it can be impossible to spread the behavior of hierarchy without changing his classes. The Visitor Pattern precisely allows the developer of a hierarchy to insert a support for cases where other developers would like to spread his behavior.

This design pattern allows an external class to reach the internal variables of other classes (going contrary to concepts of POO). This model is useful when they have a reasonable number of instances of a small number of classes and that we want to perform operations which implicate them all (or many of them).

If deporting operations contained in a class towards another one can seem bad for POO, there are good reasons to make it. Indeed, if these operations are identical for every class instead of duplicating this method it is preferable to put these operations in a visitor (operation centralization). The visitor will use then the internal data of every object to perform asked operation.

In practice, the Visitor Pattern is realized in the following way: every class that can be “visited” must make available a public method « accept » taking as argument an object of type “visitor”. The « accept » method will call the « visit » method of the visitor object with the visited object as argument. In that way, a visitor object will be able to know the reference of the visited object and call his public methods to acquire data necessary for the treatment to perform (counting, generation of report, etc).

Visitor Pattern - UML

Here is an example to make the whole thing much more understandable 😉

Let’s create a hierarchy: We will define a house in which we will put a list of house elements (living room, bathroom, bedroom, garden, garage…) and implements the visitor pattern in this hierarchy…

First, let’s define the visit able interface to make our house elements able to accept the visitor:

public interface IHouseElement {
public void accept(IVisitor visitor);
}

Then, let’s define the house and its elements:

public class Garden implements IHouseElement {
private int sq_ft;
private boolean swimmingPool;
public int getSq_ft() {
return sq_ft;
}
public boolean hasSwimmingPool() {
return swimmingPool;
}
public Garden(int sq_ft, boolean swimmingPool) {
this.sq_ft = sq_ft;
this.swimmingPool = swimmingPool;
}
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}

public class CarPark implements IHouseElement {
private int carNb;
public int getCarNb() {
return carNb;
}
public CarPark(int carNb) {
this.carNb = carNb;
}
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}

public class Room implements IHouseElement {
private String name;
private int sq_ft;
public String getName() {
return name;
}
public int getSq_ft() {
return sq_ft;
}
public Room(String name, int sq_ft) {
this.name = name;
this.sq_ft = sq_ft;
}
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}

public class Bedroom extends Room {
private int bedNb;
public int getBedNb() {
return bedNb;
}
public Bedroom(String name, int sq_ft, int bedNb) {
super(name, sq_ft);
this.bedNb = bedNb;
}
public void accept(IVisitor visitor) {
visitor.visit((Room) this);
visitor.visit(this);
}
}

public class Bathroom extends Room {
private int showerNb;
private int bathNb;
public int getShowerNb() {
return showerNb;
}
public int getBathNb() {
return bathNb;
}
public Bathroom(String name, int sq_ft, int showerNb, int bathNb) {
super(name, sq_ft);
this.showerNb = showerNb;
this.bathNb = bathNb;
}
public void accept(IVisitor visitor) {
visitor.visit((Room) this);
visitor.visit(this);
}
}

public class House {
private String name;
private IHouseElement[] houseElements;
public String getName() {
return name;
}
public IHouseElement[] getHouseElements() {
return houseElements;
}
public House() {
this.name = "My house";
this.houseElements = new IHouseElement[] {
new Room("Living room", 600),
new Bedroom("first bedroom", 300, 1),
new Bathroom("little bathroom", 100, 1, 0),
new Bedroom("second bedroom", 500, 1),
new Bathroom("big bathroom", 400, 1, 1),
new Garden(1200, true),
new CarPark(1)};
}
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}

Next we have to define the visitor interface and we’ll create two different possible visitor implementations.

public interface IVisitor {
public void visit(House house);
public void visit(Room room);
public void visit(Bathroom bathroom);
public void visit(Bedroom bedroom);
public void visit(Garden garden);
public void visit(CarPark carPark);
}

First implementation: Visit the house and list its elements

public class PrintVisitor implements IVisitor {
public void visit(House house) {
System.out.println("Visiting house: "+house.getName());
for(IHouseElement room : house.getHouseElements()) {
room.accept(this);
}
System.out.println("House visited...\n");
}
public void visit(Room room) {
System.out.println("Visiting room: "+room.getName()+" ("+room.getSq_ft()+" sq ft)");
}
public void visit(Bathroom bathroom) {
System.out.println("  – "+bathroom.getShowerNb()+" shower(s)");
System.out.println("  – "+bathroom.getBathNb()+" bath(s)");
}
public void visit(Bedroom bedroom) {
System.out.println("  – "+bedroom.getBedNb()+" bed(s)");
}
public void visit(Garden garden) {
System.out.println("Visiting Garden: ");
if(garden.hasSwimmingPool())
System.out.println("  – With a swimming pool");
}
public void visit(CarPark carPark) {

System.out.println("Visiting CarPark: ");
System.out.println("  – "+carPark.getCarNb()+" parking place(s)");
}
}

Second implementation: Visit the house to get its total surface

public class SurfaceVisitor implements IVisitor {
private int totalSqFt;
public SurfaceVisitor() {
this.totalSqFt = 0;
}
public void visit(House house) {
System.out.println("Visiting house: "+house.getName());
for(IHouseElement room : house.getHouseElements()) {
room.accept(this);
}
System.out.println("\nHouse total surface = "+totalSqFt+" sq ft\n");
}
public void visit(Room room) {
System.out.println("Visiting room: "+room.getName());
System.out.println(" – "+room.getSq_ft()+" = "+(this.totalSqFt += room.getSq_ft()));
}
public void visit(Bathroom bathroom) {
// nothing to do
}
public void visit(Bedroom bedroom) {
// nothing to do
}
public void visit(Garden garden) {
System.out.println("Visiting Garden: ");
System.out.println(" – "+garden.getSq_ft()+" = "+(this.totalSqFt += garden.getSq_ft()));
}
public void visit(CarPark carPark) {
// nothing to do
}
}

Finally, run a little test:

public class Test {
public static void main(String[] args) {
House house = new House();
IVisitor printVisitor = new PrintVisitor();
IVisitor surfaceVisitor = new SurfaceVisitor();
house.accept(printVisitor);
System.out.println("-");
house.accept(surfaceVisitor);
}
}

Here is the output:

Visiting House: My house
Visiting Room: Living room (600 sq ft)
Visiting Room: first bedroom (300 sq ft)
  – 1 bed(s)
Visiting Room: little bathroom (100 sq ft)
  – 1 shower(s)
  – 0 bath(s)
Visiting Room: second bedroom (500 sq ft)
  – 1 bed(s)
Visiting Room: big bathroom (400 sq ft)
  – 1 shower(s)
  – 1 bath(s)
Visiting Garden
  – With a swimming pool
Visiting CarPark
  – 1 parking place(s)
House visited...


Visiting House: My house
Visiting Room : Living room
– 0 + 600 = 600
Visiting Room : first bedroom
– 600 + 300 = 900
Visiting Room : little bathroom
– 900 + 100 = 1000
Visiting Room : second bedroom
– 1000 + 500 = 1500
Visiting Room : big bathroom
– 1500 + 400 = 1900
Visiting Garden
– 1900 + 1200 = 3100

House total surface = 3100 sq ft

This example show you the power and the interest of this pattern. But you’ve got to take care; Even if the visitor pattern is great, he has some limits: He is very dependent of the data structure.

Look at our house example: Let’s imagine that the Bedroom and Bathroom classes are not implemented in the IVisitor interface. The Bedroom and Bathroom instance would never been visited, so we wouldn’t be able to distinguish those two different type of Room. Of course you will say that to avoid this problem we just have to take care to include all the subclasses of our hierarchy in the visitor interface (like we do in the example). But if our data structure improves? For example if a new Room type is defined in the future, you won’t be able to visit it without redefining the IVisitor interface :).

Another problem is the risks present in the data structure itself. If you develop a visitor without knowing the code of the visited hierarchy, you can’t be aware of everything concerning the original behavior of this hierarchy and the way it’s coding, so you can get trapped.

So keep in mind that the Visitor Pattern is much more powerful with the following conditions:

  • All the types of nodes are stable
  • A common change is the addition of new functions that apply to different nodes

I hope that now you are aware of what’s the Visitor Pattern 😉

Advertisements

21 Responses to “The Visitor Pattern”

  1. […] ] Open Question : Simple Java GUI ProgramAdd click listener to a ListView to show YouTube VideoThe Visitor Pattern .recentcomments a{display:inline !important;padding:0 !important;margin:0 […]

  2. Marina said

    It’s an amazing piece of writing in support of all the web visitors; they will obtain advantage from it I am sure.

  3. It’s really very complicated in this active life to listen news on Television, so I simply use web for that reason, and get the latest news.

  4. Paris said

    hey there and thank you for your info – I’ve certainly picked up anything new from right here. I did however expertise several technical points using this site, since I experienced to reload the website a lot of times previous to I could get it to load properly. I had been wondering if your web hosting is OK? Not that I am complaining, but slow loading instances times will sometimes affect your placement in google and could damage your quality score if ads and marketing with Adwords. Anyway I’m adding this
    RSS to my email and could look out for a lot
    more of your respective fascinating content. Ensure that
    you update this again very soon.

  5. Jerry said

    Awesome! Its truly awesome paragraph, I have got much clear idea
    about from this piece of writing.

  6. When you are looking at clearing up acne,
    you need to have a “don’t quit attitude”. Obviously dubious on this claim, I decided it didn’t hurt to try this product to up several unsightly pimples that were not being helped by Clearasil. We are very well aware of the horrors and down tales of such whom are suffering from this embarrassing and annoying skin condition.

  7. Lukas said

    It is not my first time to go to see this web site,
    i am visiting this site dailly and obtain nice data from here
    everyday.

  8. Since the demand is very high and the supply is likewise high
    the price tends to go down. ¨ Don’t waste your money trying to buy lists of video game distribution companies. If you decide to start an online clothing business, keep these 5 business secrets of successful businessmen to help you find the best wholesale clothing companies who can offer you the best deals.

  9. This design is steller! You definitely know how to keep a reader amused.
    Between your wit and your videos, I was almost moved to
    start my own blog (well, almost…HaHa!) Wondeful job. I really enjoyed what you had to say, and
    more than that, how you presented it. Too cool!

  10. Ophelia said

    I’m really enjoying the theme/design of your weblog.
    Do you ever run into any internet browser compatibility issues?
    A small number of my blog audience have
    complained about my website not working correctly in Explorer but looks great
    in Safari. Do you have any solutions to help fix this problem?

  11. I really like your blog.. very nice colors & theme.
    Did you make this website yourself or did you hire someone to
    do it for you? Plz respond as I’m looking to construct my own blog and
    would like to know where u got this from. thanks

  12. You ought to be a part of a contest for one of the greatest blogs
    on the web. I’m going to recommend this blog!

  13. I got this site from my pal who informed me about this web site and now this time I am browsing this site and reading very informative articles or reviews at this
    time.

  14. That’d be pretty awesome. You should reduce your
    consumption 5:2 metoden of sweets, stimulants including caffeine and tobacco, alcohol consumption,
    meats, dairy products, fats and all you could possibly desire.
    The above study also concluded that people who practice intermittent fasting correctly actually live longer too.
    A vegan diet plan is working! Although it would
    seem like the best way for SNSD to thank the people in attendance from far away.

  15. Hello everyone, it’s my first go to see at this web page, and post is really fruitful in favor of me, keep up posting such articles.

  16. Wow, marvelous weblog structure! How lengthy have you ever been blogging for?

    you make running a blog glance easy. The total glance of your
    website is wonderful, as smartly as the content!

  17. If you are involved with Online Marketing and advertising about
    the previous couple of decades, you will know (if you have not
    been dwelling on the moon). There’s plenty
    of newsletters out there being run by your average person, a hobbyist who is passionate about a topic, that will happily accept
    a small payment in exchange for putting my advertisement in their Ezine.
    Develop Willie’s discipline in yourself and you’ll be well on your way to being successful.

  18. They’d stood at the door, you can even earn up to 20 percent
    cash back short term car insurance on gas and road essentials.

    Since everyday credit actions, from using your credit card, but would receive
    letters telling them their accounts had been transferred to
    the bank and negotiate for a higher credit risk. There are two kinds of loans and credit limits.
    84 per cent Visa fee is levied on top of the page to be notified of new
    Vancouver car buying articles.

  19. coffee recipes

    The Visitor Pattern « The Coffee Machine

  20. As the Cherry Blossom season coincides with both the
    fiscal and calendar years in Japan, it marks the
    arrival of new beginnings – students start their first day of school and new employees start their first day of work.
    “Beauty and The Beat,” is currently being shown at the online French film festival, My French Film Festival.
    Anybody who comes to France to learn will most definitely end up pleased
    by the experience.

  21. One of the most important aspect of gaming hardware is the computer mouse which is not
    less than a lifeline for a professional gamer because most of the game control
    is achieved through mouse and keyboard. You can certainly get exactly what you want, but you might also find the huge
    variety of options confusing. Motherboard that accepts
    the fast processor is required.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

 
%d bloggers like this: