31. Composite

image

© Jennifer M. Kohnke

A composite is a euphemism for a lie. It’s disorderly. It’s dishonest and it’s not journalism.

—Fred W. Friendly, 1984

The COMPOSITE pattern is a very simple pattern that has significant implications. The fundamental structure of the COMPOSITE pattern is shown in Figure 31-1. Here, we see a hierarchy based on shapes. The Shape base class has two derivative shapes: Circle and Square. The third derivative is the composite. CompositeShape keeps a list of many Shape instances. When called on CompositeShape, Draw() delegates that method to all the Shape instances in the list.

Figure 31-1. COMPOSITE pattern

image

Thus, an instance of CompositeShape appears to the system to be a single Shape. It can be passed to any function or object that takes a Shape, and it will behave like a Shape. However, it is really a proxy1 for a group of Shape instances. Listings 31-1 and 31-2 show one possible implementation of CompositeShape.


Listing 31-1. Shape.cs

public interface Shape
{
  void Draw();
}



Listing 31-2. CompositeShape.cs

using System.Collections;

public class CompositeShape : Shape
{
  private ArrayList itsShapes = new ArrayList();
  public void Add(Shape s)
  {
    itsShapes.Add(s);
  }

  public void Draw()
  {
    foreach (Shape shape in itsShapes)
      shape.Draw();
  }
}


Composite Commands

Consider our discussion of Sensors and Command objects in Chapter 21. Figure 21-3 showed a Sensor class using a Command class. On detecting its stimulus, the Sensor called Do() on the Command.

What I failed to mention then was that often, a Sensor had to execute more than one Command. For example, when it reached a certain point in the paper path, the paper would trip an optical sensor. That sensor then stopped a motor, started another, and engaged a particular clutch.

At first, we took this to mean that every Sensor class would have to maintain a list of Command objects (see Figure 31-2). However, we soon recognized that whenever it needed to execute more than one Command, a Sensor always treated those Command objects identically. That is, it simply iterated over the list and called Do() on each Command. This was ideal for the COMPOSITE pattern.

Figure 31-2. Sensor containing many Commands

image

So we left the Sensor class alone and created a CompositeCommand, as shown in Figure 31-3. This meant that we didn’t have to change the Sensor or the Command. We were able to add the plurality of Commands to a Sensor without changing either. This is an application of OCP.

Figure 31-3. CompositeCommand

image

Multiplicity or No Multiplicity

This leads to an interesting issue. We were able to make our Sensors behave as though they contained many Commands, without having to modify the Sensors. There must be many other situations like this in normal software design. There must be times when you could use COMPOSITE rather than building a list or vector of objects.

In other words, the association between Sensor and Command is 1:1. We were tempted to change that association to 1:many. But instead, we found a way to get 1:many behavior without a 1:many relationship. A 1:1 relationship is much easier to understand, code, and maintain than a 1:many relationship is, so this was clearly the right design tradeoff. How many of the 1:many relationships in your current project could be 1:1 if you used COMPOSITE?

Of course, not all 1:many relationship can be reverted to 1:1 by using COMPOSITE. Only those in which every object in the list is treated identically are candidates. For example, if you maintained a list of employees and searched through that list for employees whose paydate is today, you probably shouldn’t use the COMPOSITE pattern, because you wouldn’t be treating all the employees identically.

Conclusion

Quite a few 1:many relationships qualify for conversion to COMPOSITE. The advantages are significant. Instead of duplicating the list management and iteration code in each of the clients, that code appears only once in the composite class.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.61.223