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

Composite

Pattern Properties

Type: Structural, Object

Level: Component

Purpose

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.

Introduction

You’ve decided to enhance the Personal Information Manager to let users manage a complex project. Features of this enhancement include defining the project as a group of tasks and related subtasks, and associating deliverables with tasks. A natural way to accomplish this from a programming perspective is to define a tree structure, where the root task (which represents the project itself) branches out to subprojects, subsubprojects, and so on. Therefore, you define a Task class that holds a collection of other Task and Deliverable objects. Since both the Task and Deliverable relate to the project, you define a common parent for them—the ProjectItem class.

However, what happens if users need to perform an action that depends on the whole tree? For example, a project manager wants a time estimate for tasks and deliverables for one project. To accommodate this, you write code to traverse the tree and call the appropriate methods at each branch. That's a lot of work, however, involving separate code to walk the tree, call the methods, and collect the results. And with different classes (Task and Deliverable) at each branch of the tree, you might need to handle them differently when getting time estimates. For a large number of classes or a complex tree, the code quickly becomes difficult to manage.

There's a better way to solve this problem. With the Composite pattern, you can use polymorphism and recursion to provide an efficient, simple, easy-to-maintain solution.

Begin by defining a standard method for all classes that provides the time estimate, called getTimeRequired. Define this method for the ProjectItem interface, and implement that behavior in all classes that are types of ProjectItem. For Deliverable, define getTimeRequired to return 0, because a deliverable does not have time associated directly with it. For the Task class, return a time consisting of the time for the task plus the sum of the getTimeRequired calls for all of the Task children.

Using this pattern, you define getTimeRequired so that it automatically calculates the project time estimates for any part of the tree. Just call the getTimeRequired method for the part of the Task needed, and the code in the method takes care of the job of traversing the tree and calculating results.

Applicability

Use the Composite pattern when:

There is a component model with a branch-leaf structure (whole-part or container-contained).

The structure can have any level of complexity, and is dynamic.

You want to treat the component structure uniformly, using common operations throughout the hierarchy.

Description

Object-oriented developers are often interested in developing components that follow a whole-part model. Whole-part model is a model that allows you to treat a collection of identical objects (the parts) as one entity (the whole). Typically, these structures should be flexible and easy to use. Users should be able to modify the structure as an application runs, adding or removing parts to suit their needs. At the same time, it’s desirable to keep the complexity of the structure hidden behind the scenes, so that users perceive only a seamless, unified product.

108