Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Applied Java™ Patterns - Stephen Stelting, Olav Maassen.pdf
Скачиваний:
202
Добавлен:
24.05.2014
Размер:
2.84 Mб
Скачать

Visitor

Pattern Properties

Type: Behavioral, Object

Level: Component to System

Purpose

To provide a maintainable, easy way to perform actions for a family of classes. Visitor centralizes the behaviors and allows them to be modified or extended without changing the classes they operate on.

Introduction

Imagine you want the Personal Information Manager to have project planning capability, and the project planner is used for things like bidding, risk analysis, and time estimation. The following classes represent a complex project:

Project – The root of the project hierarchy, representing the project itself

Task – A work step in the project

DependentTask – A work step that depends on other tasks for its own completion

Deliverable: An item or document to be produced as a result of the project

To clearly identify these classes as part of a common model, they’re organized around an interface called

ProjectItem.

So far so good. Now, how do you code the ability to estimate the total cost for the project? The calculation will probably depend on the specific type of ProjectItem. In that interface you define a method getCost that should calculate the costs for that specific part of the project. This would allow you to compute the cost for every item in the project structure.

You might decide on an approach like this:

Project – No operation, since the cost is equal to the cost of all other project items.

Simple task – Cost is based on estimated hours of effort.

Dependent task – Same as simple task, but adds an additional factor to represent coordination based on the task dependencies.

Deliverable – Cost is a basic estimate of materials plus production cost.

However, how should you calculate the time required for the project, and project risk? Using the same approach as for the cost makes the code harder to maintain. With every new capability, you have to write a bunch of new methods that are spread throughout the project classes. With every new operation, the classes become larger, more complex, and harder to understand.

It is also difficult to keep track of information with this kind of approach. If you try to estimate cost, time, or risk using localized methods, you have to figure out how to maintain the intermediate results, since each method belongs to a specific project object. You will likely wind up passing the information through the entire project tree, then crossing your fingers and hoping that you’ll never have to debug it.

The Visitor pattern offers an alternative. You define a single class, with a name like CostProjectVisitor, that performs all cost-related calculations. Instead of computing cost in the ProjectItems themselves, you pass them to the Visitor class, which keeps a running tally of the total cost.

ProjectItems no longer has a getCost method. Instead, it has a more generic acceptVisitor method that uses a ProjectVisitor to call a specific method on the ProjectVisitor. For instance, the acceptVisitor method

86