Lecture 19: Visitors

Ambient Temperature: 73.8oF

Concepts

  1. A representative from Palantir Technologies came to talk about their company and encourage attendance of their info session tonight from 5:30pm to 6:50pm in Duncan Hall 1064. The advertised dinner will consist of Star Pizza.
  2. Interpreter Design Pattern:
    1. An abstract class for a category of objects defines an abstract interface that each concrete subclass implements in its own way. Our first design of Shapes, with an AShape defining a paint() method, was an example of this design pattern.
    2. To add behavior to the category of objects, you add a method to the abstract interface. (To add behavior to an AShape, you would add a method to the AShape class.)
    3. A problem arises if we have lots of behaviors: If we have 300 different behaviors, our class will have 300 different methods.
    4. Another problem arises if we want to change the behavior at runtime: All of these methods and their code are determined at compile-time, and we can’t change that.
    5. A third problem arises if we want to allow third-parties to add behaviors: Since all of the behavior was written by us and compiled into the .class files, third parties cannot easily add behaviors into existing objects.
    6. All of these problems can be summarized by the following idea: The algorithms are tied to the data structure. These problems are solved by the
  3. Visitor Design Pattern:  The interface for a category of objects simply states that it accepts “a visitor for this category of objects.” Algorithms are encapsulated inside visitors. When an object accepts a visitor, it provides information to the visitor as determined by the Visitor’s interface, and calls the visitor’s algorithm. The key points of implementation are illustrated on the lecture webpage, and described below:
    1. The IBall interface defines public <T> T accept(IBallVisitor<T> _visitor);
    2. The IBallVisitor<T> interface defines a method for each logical sub-type of an IBall. For example, if there are three concrete ball types: ImageBall, PaintedBall, and CompositeBall, the IBallVisitor<T> will define
      public T ImageBallCase(ImageBall _b);
      public T PaintedBallCase(PaintedBall _b);
      public T CompositeBallCase(CompositeBall _b);
      public T DefaultCase(IBall _b);
    3. ImageBall will implement its accept method as
      public <T> T accept(IBallVisitor<T> _visitor) {
           return _visitor.ImageBallCase(this);
      }
      and so forth.
    4. If a new type of ball that doesn’t have its own special case in the visitor still wants to participate, it uses the DefaultCase method.
    5. As a result, an algorithm that runs properly on any collection of IBalls can be encapsulated inside an IBallVisitor. Adding algorithms does not require modifying the data structures (IBalls or their concrete subclasses), and anyone, even third-parties, can add new algorithms at any (compile or run) time.
    6. An added benefit is that an unknown algorithm (IBallVisitor<T>, but you don’t know which concrete implementation) can be run on an unknown host (IBall, but you don’t know which concrete implementation), and the actual code that is run will be the correct method in the concrete visitor with the host available as a parameter with a specific, concrete type. This lets you write fully-generic, abstract, type-safe and type-checked algorithms without relying on instanceof or reflection.
  4. If a task depends on an object, delegate the completion of that task to the object.

Quotes

  1. “plumber dot fix toilet” – Dr. Wong

Resources

  1. Lecture 19 Webpage: http://www.clear.rice.edu/comp310/f12/lectures/lec19/