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

Visitor

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 A.117 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 A.118 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,

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 A.119 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.}

282

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 A.120 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; }

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; }

19.

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 A.121 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.

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

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

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

283

19. public double getTimeRequired(){ return timeRequired; }

20.

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

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

23.public void setTimeRequired(double newTimeRequired){ timeRequired =

newTimeRequired; }

24.

25.public void addProjectItem(ProjectItem element){

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 A.122 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 classes that implement the ProjectVisitor interface and perform some computation on project items. The class ProjectCostVisitor shows how project cost calculations could be managed.

Example A.123 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.

The Contact interface and ContactImpl class represent the owner for a Task or Deliverable.

Example A.124 Contact.java

1. import java.io.Serializable;

284

2.public interface Contact extends Serializable{

3.public static final String SPACE = " ";

4.public String getFirstName();

5.public String getLastName();

6.public String getTitle();

7.public String getOrganization();

8.

9.public void setFirstName(String newFirstName);

10.public void setLastName(String newLastName);

11.public void setTitle(String newTitle);

12.public void setOrganization(String newOrganization);

13.}

Example A.125 ContactImpl.java

1.public class ContactImpl implements Contact{

2.private String firstName;

3.private String lastName;

4.private String title;

5.private String organization;

6.

7.public ContactImpl(){}

8.public ContactImpl(String newFirstName, String newLastName,

9.String newTitle, String newOrganization){

10. firstName = newFirstName;

11. lastName = newLastName;

12. title = newTitle;

13. organization = newOrganization;

14. }

15.

16.public String getFirstName(){ return firstName; }

17.public String getLastName(){ return lastName; }

18.public String getTitle(){ return title; }

19.public String getOrganization(){ return organization; }

21.public void setFirstName(String newFirstName){ firstName = newFirstName; }

22.public void setLastName(String newLastName){ lastName = newLastName; }

23.public void setTitle(String newTitle){ title = newTitle; }

24.public void setOrganization(String newOrganization){ organization = newOrganization; }

26.public String toString(){

27.return firstName + SPACE + lastName;

28.}

29.}

DataCreator is a support class which generates a sample Project and saves it to a file. The DataRetriever class loads the data from the file, restoring the saved Project.

Example A.126 DataCreator.java

1.import java.io.Serializable;

2.import java.io.ObjectOutputStream;

3.import java.io.FileOutputStream;

4.import java.io.IOException;

5.public class DataCreator{

6.private static final String DEFAULT_FILE = "data.ser";

8.public static void main(String [] args){

9.String fileName;

10.if (args.length == 1){

11. fileName = args[0];

12.}

13.else{

14. fileName = DEFAULT_FILE;

15.}

16.serialize(fileName);

17.}

18.

19.public static void serialize(String fileName){

20.try{

21. serializeToFile(createData(), fileName);

22.}

23.catch (IOException exc){

24. exc.printStackTrace();

25.}

26.}

28. private static Serializable createData(){

285