Browse DevX
Sign up for e-mail newsletters from DevX


Extending Behavior with the Visitor Pattern

One common problem involves adding or extending behavior after—sometimes long after—you've implemented a class. A similar problem requires you to tack on behavior dependent on the features of a class but that doesn't belong to that class. Both problems have the Visitor pattern written all over them—and if you implement it, you'll find that the Visitor pattern provides excellent results.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

s an architect working for my own company and the president of the Greater Lansing area .NET Users Group (glugnet.org) I'm constantly looking for customers and trying to increase technology awareness in the greater community. In essence, like every business person I am always looking for customers. A natural extension of my consulting business is matching employees to employers. As a result I began working on Motown-Jobs, a Web site where job seekers can post resumes and search for jobs posted by job owners (employers). When writing down the use cases for Motown-Jobs, I knew that I was very familiar with some aspects of matching employers to employees as I had been doing it for years. I was also sure that I might miss ways to capitalize on business opportunities because of expertise I didn’t have. To deal with my limited expertise and anticipate future revisions I hedged when I designed Motown-Jobs. Let me explain.

I want Motown-Jobs to permit employers to post jobs for a fee and employees to post resumes and search for jobs for free. I also suspect employers may want to know about the traffic their job listings generate, and future advertisers might be interested in general site traffic. In fact, site statistics of all kinds might be useful in unanticipated ways. When you can anticipate that a system may require changes but can't define exactly what those changes will be, the challenge becomes one of programming defensively.

In this context, defensive programming means that you may want to add future behavior but without changing core classes constantly. For example, if a Job class is central to the system, then repeatedly updating the Job class would be disruptive. To respond to this potentiality defensively and proactively you can employ the Visitor behavior pattern. Think of the Visitor pattern as you would a census taker approaching a household. The census taker shows up, gathers some information, and goes away. (The going away part is good.) You could just as easily substitute the census taker with a garbage man, maid, repairman, or a favorite rich aunt who cleans all the time. The point is that the nature of a household—the number of walls, rooms, furniture, and regular occupants—doesn't change that much; the visitor can drop in, do what that particular kind of visitor does—take census information, clean your house, or leave cash—and go away.

Interestingly enough, this metaphor holds up nicely because a visitor can be anything and do anything without changing the nature of the host. In this metaphor, the household plays host to any number and variety of visitors. Enough said.

Defining Hosts and Visitors
The Motown-Jobs code defines important classes for job listings, resumes, and advertisements. Each of these classes contains information about their contents. Job listing classes, for example, might contain information about the number of times they were viewed, when they were posted, and their individual expiration dates. You can define classes such as job listing and advertisement to have a relative dollar value. For job listing and advertisement you may want to determine the value of the time remaining for each listing. Finally, the future may hold new, useful, and valuable ways to use the data represented by instances of job listing, advertisement, and resume. From the perspective of the visitor pattern these classes represent hosts. In the future you may want to define new ways to drop in (visit) and collect information about instances of these classes.

The point is that by defining a facet of job listing, resume, and advertisement generically as hosts you can later define specific visitor classes to drop in and perform operations on instances of these classes.

Technically, implementing the Visitor pattern is quite straightforward. You define an abstract class or interface named Host—or IHost for interfaces—that has a single method named Accept that accepts a Visitor abstract class or an interface. Each Visitor contains methods called Visit for each kind of Host. You call the Host's Accept method, passing in the Visitor, and the Host's Accept method calls the Visitor.Visit method for that kind of Host. You code the Visit method for each Host to glean the information or perform the extended operation on the Host. The important point is that after implementing the Accept method you don't need to change the hosts to add new behavior.

This kind of method dispatching is called double dispatching. You use double dispatching because hosts know only that visitors will be visiting and visitors know only that the host will ask the visitor to stay and visit. This interchange looks loosely like:

//Visitor: knock-knock Host.Accept(visitor) //Host: Hello, come on in and visit for a spell Visitor.Visit(this)

Subsequently, the visitor runs around poking at all your stuff and asking questions.

If all these folksy analogies aren't helping, perhaps the UML class diagram for the Visitor pattern will clear it up for you. I encourage you to pick up a copy of the Gang of Four book, Design Patterns, published by Addison Wesley.

Thanks for your registration, follow us on our social networks to keep up-to-date