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

Factory Method (page 21) – Template methods often call Factory Methods to create new instances without knowing the exact class being created.

Strategy (page 114) – The Strategy pattern uses composition to completely replace behavior, while the Template Method pattern uses inheritance to replace parts of the behavior.

Intercepting Filter [CJ2EEP] – The Intercepting Filter uses the Template Method pattern to implement its Template Filter Strategy.

Example

Note:

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

This example uses project classes from the Personal Information Manager to illustrate the Template Method.

ProjectItem is the abstract class that defines the Template Method in this demonstration. Its method getCostEstimate returns a total value for the project item that is calculated using the following equation:

time estimate * hourly rate + materials cost

The hourly rate is defined in the ProjectItem class (using the rate variable, getter and setter methods in the class), but the methods getTimeRequired and getMaterialsCost are abstract. This requires the subclasses to override them, providing their own way to calculate the values.

Example 2.52 ProjectItem.java

1.import java.io.Serializable;

2.public abstract class ProjectItem implements Serializable{

3.private String name;

4.private String description;

5.private double rate;

6.

7.public ProjectItem(){}

8.public ProjectItem(String newName, String newDescription, double newRate){

9.name = newName;

10.description = newDescription;

11.rate = newRate;

12.}

13.

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

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

16.public void setRate(double newRate){ rate = newRate; }

17.

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

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

20.public final double getCostEstimate(){

21.return getTimeRequired() * getRate() + getMaterialsCost();

22.}

23.public double getRate(){ return rate; }

24.

25. public String toString(){ return getName(); }

26.

27.public abstract double getTimeRequired();

28.public abstract double getMaterialsCost();

29.}

The Deliverable class represents a concrete product of some kind. Because it represents a physical item, the value returned by its getTimeRequired method is a fixed amount. Similarly, the getMaterialsCost method returns a fixed value.

Example 2.53 Deliverable.java

1.public class Deliverable extends ProjectItem{

2.private double materialsCost;

3.private double productionTime;

95

4.

5.public Deliverable(){ }

6.public Deliverable(String newName, String newDescription,

7.double newMaterialsCost, double newProductionTime,

8.double newRate){

9.super(newName, newDescription, newRate);

10.materialsCost = newMaterialsCost;

11.productionTime = newProductionTime;

12.}

13.

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

15.public void setProductionTime(double newTime){ productionTime = newTime; }

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

18.public double getTimeRequired(){ return productionTime; }

19.}

The Task class represents a job that can consist of any number of subtasks or deliverables. For this reason, getTimeRequired calculates the total time for the Task and all its children by iterating through its list of project items and calling the getTimeRequired method. The method getMaterialsCost follows a similar strategy, working through the list of project items and calling each child’s getMaterialsCost method.

Example 2.54 Task.java

1.import java.util.ArrayList;

2.import java.util.Iterator;

3.public class Task extends ProjectItem{

4.private ArrayList projectItems = new ArrayList();

5.private double taskTimeRequired;

6.

7.public Task(){ }

8.public Task(String newName, String newDescription,

9.double newTaskTimeRequired, double newRate){

10.super(newName, newDescription, newRate);

11.taskTimeRequired = newTaskTimeRequired;

12.}

13.

14.public void setTaskTimeRequired(double newTaskTimeRequired) { taskTimeRequired =

newTaskTimeRequired; }

15.public void addProjectItem(ProjectItem element){

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

17. projectItems.add(element);

18.}

19.}

20.public void removeProjectItem(ProjectItem element){

21.projectItems.remove(element);

22.}

23.

24.public double getTaskTimeRequired(){ return taskTimeRequired; }

25.public Iterator getProjectItemIterator(){ return projectItems.iterator(); }

26.public double getMaterialsCost(){

27.double totalCost = 0;

28.Iterator items = getProjectItemIterator();

29.while (items.hasNext()){

30. totalCost += ((ProjectItem)items.next()).getMaterialsCost();

31.}

32.return totalCost;

33.}

34.public double getTimeRequired(){

35.double totalTime = taskTimeRequired;

36.Iterator items = getProjectItemIterator();

37.while (items.hasNext()){

38. totalTime += ((ProjectItem)items.next()).getTimeRequired();

39.}

40.return totalTime;

41.}

42.}

96

Chapter 3. Structural Patterns

Introduction to Structural Patterns

Structural patterns describe effective ways both to partition and to combine the elements of an application. The ways structural patterns affect applications varies widely: for instance, the Adapter pattern can let two incompatible systems communicate, while Facade lets you present a simplified interface to a user without removing all the options available in the system.

Adapter – To act as an intermediary between two classes, converting the interface of one class so that it can be used with the other.

Bridge – To divide a complex component into two separate but related inheritance hierarchies: the functional abstraction and the internal implementation. This makes it easier to change either aspect of the component.

Composite – To develop a flexible way to create hierarchical tree structures of arbitrary complexity, while enabling every element in the structure to operate with a uniform interface.

Decorator – To provide a way to flexibly add or remove component functionality without changing its external appearance or function.

Facade – To provide a simplified interface to a group of subsystems or a complex subsystem.

Flyweight – To reduce the number of very low-level, detailed objects within a system by sharing objects.

Half-Object Plus Protocol (HOPP) – To provide a single entity that lives in two or more address spaces.

Proxy – To provide a representative of another object, for reasons such as access, speed, or security.

97