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

The Element classes do not have to know the details of specific Visitors, but a ConcreteVisitor generally does have to know the details of the Element classes. To perform a given function or calculation, the Visitor frequently must use the methods of the Element classes in order to accomplish its task.

Pattern Variants

As with many patterns, you can represent the Element and Visitor as either abstract classes or interfaces in Java.

Another decision you need to make is how to apply the Visitor to a collection of Elements. It's important to stress that the Visitor pattern makes no assumptions about the structure of the Elements it operates on. You can use a ConcreteVisitor equally effectively to traverse a simple collection, a chain structure, a list, or a tree.

Although some implementations of the Visitor place the traversal code within the ConcreteVisitor itself, the pattern doesn’t require this. It is equally valid to use an external class, like an Iterator, to move through a collection. You can then pair the Visitor with the Iterator as required.

Related Patterns

Related patterns include the following. You also can use a number of patterns in conjunction with the Visitor to traverse various kinds of collections of Elements:

Interpreter (page 59) – You can use the Visitor pattern to centralize the interpretation operation.

Iterator (page 69) – You can use the Iterator pattern to traverse a generic collection.

Composite (page 157) – You can combine the Composite with Visitor to walk a tree structure.

Example

Note:

For a full working example of this code example, with additional supporting classes and/or a RunPattern class, see “ Visitor ” on page 432 of the “ Full Code Examples ” appendix.

The Visitor pattern is often useful when operations must be performed over a large structure, and composite results must be calculated. In this demonstration, the Visitor pattern is used to calculate the total cost for a project.

Four classes are used to represent project elements, and all of the classes implement a common interface, ProjectItem. In this example, ProjectItem defines the accept method required to host a Visitor.

Example 2.45 ProjectItem.java

1.import java.io.Serializable;

2.import java.util.ArrayList;

3.public interface ProjectItem extends Serializable{

4.public void accept(ProjectVisitor v);

5.public ArrayList getProjectItems();

6.}

The Project class represents the project itself, the Deliverable class a concrete product, the Task: a job of some sort. In addition, there is a subclass of Task called DependentTask. This class holds a set of other Tasks upon which it depends for its own completion.

Example 2.46 Deliverable.java

1.import java.util.ArrayList;

2.public class Deliverable implements ProjectItem{

3.private String name;

4.private String description;

5.private Contact owner;

6.private double materialsCost;

7.private double productionCost;

8.

9.public Deliverable(){ }

10.public Deliverable(String newName, String newDescription,

89

11.Contact newOwner, double newMaterialsCost, double newProductionCost){

12.name = newName;

13.description = newDescription;

14.owner = newOwner;

15.materialsCost = newMaterialsCost;

16.productionCost = newProductionCost;

17.}

18.

19.public String getName(){ return name; }

20.public String getDescription(){ return description; }

21.public Contact getOwner(){ return owner; }

22.public double getMaterialsCost(){ return materialsCost; }

23.public double getProductionCost(){ return productionCost; }

25.public void setMaterialsCost(double newCost){ materialsCost = newCost; }

26.public void setProductionCost(double newCost){ productionCost = newCost; }

27.public void setName(String newName){ name = newName; }

28.public void setDescription(String newDescription){ description = newDescription; }

29.public void setOwner(Contact newOwner){ owner = newOwner; }

30.

31.public void accept(ProjectVisitor v){

32.v.visitDeliverable(this);

33.}

34.

35.public ArrayList getProjectItems(){

36.return null;

37.}

38.}

Example 2.47 DependentTask.java

1.import java.util.ArrayList;

2.public class DependentTask extends Task{

3.private ArrayList dependentTasks = new ArrayList();

4.private double dependencyWeightingFactor;

5.

6.public DependentTask(){ }

7.public DependentTask(String newName, Contact newOwner,

8.double newTimeRequired, double newWeightingFactor){

9.super(newName, newOwner, newTimeRequired);

10.dependencyWeightingFactor = newWeightingFactor;

11.}

12.

13.public ArrayList getDependentTasks(){ return dependentTasks; }

14.public double getDependencyWeightingFactor(){ return dependencyWeightingFactor; }

16.public void setDependencyWeightingFactor(double

newFactor){ dependencyWeightingFactor = newFactor; }

17.

18.public void addDependentTask(Task element){

19.if (!dependentTasks.contains(element)){

20. dependentTasks.add(element);

21.}

22.}

24.public void removeDependentTask(Task element){

25.dependentTasks.remove(element);

26.}

27.

28.public void accept(ProjectVisitor v){

29.v.visitDependentTask(this);

30.}

31.}

Example 2.48 Project.java

1.import java.util.ArrayList;

2.public class Project implements ProjectItem{

3.private String name;

4.private String description;

5.private ArrayList projectItems = new ArrayList();

7.public Project(){ }

8.public Project(String newName, String newDescription){

9.name = newName;

10.description = newDescription;

11.}

12.

13. public String getName(){ return name; }

90

14.public String getDescription(){ return description; }

15.public ArrayList getProjectItems(){ return projectItems; }

17.public void setName(String newName){ name = newName; }

18.public void setDescription(String newDescription){ description = newDescription; }

20.public void addProjectItem(ProjectItem element){

21.if (!projectItems.contains(element)){

22. projectItems.add(element);

23.}

24.}

26.public void removeProjectItem(ProjectItem element){

27.projectItems.remove(element);

28.}

29.

30.public void accept(ProjectVisitor v){

31.v.visitProject(this);

32.}

33.}

Example 2.49 Task.java

1.import java.util.ArrayList;

2.public class Task implements ProjectItem{

3.private String name;

4.private ArrayList projectItems = new ArrayList();

5.private Contact owner;

6.private double timeRequired;

7.

8.public Task(){ }

9.public Task(String newName, Contact newOwner,

10.double newTimeRequired){

11.name = newName;

12.owner = newOwner;

13.timeRequired = newTimeRequired;

14.}

15.

public String getName(){ return name; }

 

 

16.

 

 

17.

public ArrayList getProjectItems(){ return projectItems; }

18.

public Contact getOwner(){ return owner; }

Y

}

19.

public double getTimeRequired(){ return timeRequired;L

20.

A

F

 

21.

public void setName(String newName){Mname = newName; }

 

22.

public void setOwner(Contact newOwner){ owner = newOwner; }

23.

public void setTimeRequired(double newTimeRequired){ timeRequired = newTimeRequired; }

24.

E

element){

 

25.

public void addProjectItem(ProjectItemT

 

26.

if (!projectItems.contains(element)){

 

 

27.

projectItems.add(element);

 

 

 

28.}

29.}

31.public void removeProjectItem(ProjectItem element){

32.projectItems.remove(element);

33.}

34.

35.public void accept(ProjectVisitor v){

36.v.visitTask(this);

37.}

38.}

The basic interface that defines the Visitor behavior is the ProjectVisitor. It defines a visit method for each of the project classes.

Example 2.50 ProjectVisitor.java

1.public interface ProjectVisitor{

2.public void visitDependentTask(DependentTask p);

3.public void visitDeliverable(Deliverable p);

4.public void visitTask(Task p);

5.public void visitProject(Project p);

6.}

With this framework in place, you can define some computation on project items. The class be managed.

the ProjectVisitor interface and perform TEAMProjectCostVisitorFLY PRESENTS shows how project cost calculations could

91

Example 2.51 ProjectCostVisitor.java

1.public class ProjectCostVisitor implements ProjectVisitor{

2.private double totalCost;

3.private double hourlyRate;

4.

5.public double getHourlyRate(){ return hourlyRate; }

6.public double getTotalCost(){ return totalCost; }

8. public void setHourlyRate(double rate){ hourlyRate = rate; }

9.

10. public void resetTotalCost(){ totalCost = 0.0; }

11.

12.public void visitDependentTask(DependentTask p){

13.double taskCost = p.getTimeRequired() * hourlyRate;

14.taskCost *= p.getDependencyWeightingFactor();

15.totalCost += taskCost;

16.}

17.public void visitDeliverable(Deliverable p){

18.totalCost += p.getMaterialsCost() + p.getProductionCost();

19.}

20.public void visitTask(Task p){

21.totalCost += p.getTimeRequired() * hourlyRate;

22.}

23.public void visitProject(Project p){ }

24.}

All behavior for the calculation, as well as variable storage, is centralized in the Visitor class. To add a new behavior, you would create a new class that implements ProjectVisitor and redefine the four visit methods.

92