Team LiB
Previous Section Next Section

Information "Flows" Along the Association "Pipeline"

Beginning modelers also tend to make the mistake of introducing undesired redundancy when it comes to attributes in general. In the association portrayed in Figure 10-42, we see that the name attribute of the Professor class is inappropriately mirrored by the chairmanName attribute of the Department class.

Click To expand
Figure 10-42: The name and chairmanName attributes are redundant.

While it's true that a Department object needs to know the name of the Professor object that chairs that Department, it's inappropriate to explicitly create a chairmanName attribute to reflect this information. Because the Department object maintains a reference to its associated Professor object as an attribute, the Department has ready access to this information any time it needs it, simply by invoking the Professor object's GetName method (or accessing the Name property, in the case of C#). This piece of information is rightfully encapsulated in the Professor class, where it belongs, and shouldn't be duplicated anywhere else. A corrected version of the preceding diagram is shown in Figure 10-43, with the redundancy eliminated.

Click To expand
Figure 10-43: The redundancy of Figure 10-42 has been eliminated.

In essence, whenever we see an association/aggregation line in a diagram, we can think of this as a conceptual "pipeline" across which information can "flow" between related objects as needed.

Note?/td>

At the analysis stage, we don't worry about the accessibility (public, private) of attributes, or of the directionality of associations; we'll assume that the values of all of the attributes reflected in a diagram are obtainable by calling the appropriate "get" methods on an object, or by alternatively accessing C# properties.

Sometimes, this "pipeline" extends across multiple objects, as illustrated by the next example.

In Figure 10-44, we have a diagram involving three classes.

Click To expand
Figure 10-44: An association "pipeline" between the Course, Section, and Professor classes.

Let's say that someone wishes to obtain a list of all of the Professors who have ever taught the Course titled "Beginning Objects." Because each Course object maintains a handle on all of its Section objects, past and present, the Course object representing Beginning Objects can ask each of its Section objects the name of the Professor who previously taught, or is currently teaching, that Section. The Section objects, in turn, each maintain a handle on the Professor object who taught/teaches the Section, and can use the Professor object's GetName method (or can access the Name property, in the case of C#) to retrieve the name. So, information flows along the association "pipeline" from the Professor objects to their associated Section objects and from there back to the Course object that we started with (see Figure 10-45).

Click To expand
Figure 10-45: Association "pipelines" can be quite elaborate!
Note?/td>

You'll learn a formal, UML-appropriate way to analyze and depict such "object conversations" in Chapter 11.

We've modeled these three classes' attributes in the code that follows, highlighting all of the association-driven attributes:

public class Course {
  // Attributes.
  // Pseudocode.
  private Collection offeredAs;        // a collection of Section object
                                       // "handles"
  private string courseName;
  private int courseNumber;
  private double creditHourValue;
  // etc.
}

public class Section {
  // Attributes.
  private Course represents;   // a "handle" on the related Course
                               // object
  private int sectionNo;
  private string dayOfWeek;
  private string timeOfDay;
  private string semester;
  private Professor taughtBy;  // a "handle" on the related Prof. object

  // etc.
}

public class Professor {
  // Pseudocode.
  private Collection sectionsTaught; // a collection of Section obj.
                                     // "handles"
  private string name;
  private string ssn;

  // etc.
}

If we knew that the Course class was going to regularly need to know who all the Professors were that had ever taught the Course, we might decide to introduce the redundant association "a Professor has taught a Course" into our diagram, as illustrated in Figure 10-46.

Click To expand
Figure 10-46: We add redundant associations when objects frequently need a more direct "pipeline" for communication.

This has the advantage of improving the speed with which a Course object can determine who has ever taught it: with the addition of the redundant association in Figure 10-46, Course objects can now talk directly to Professor objects without using Section objects as "go-betweens"—but the cost of this performance improvement is that we've just introduced additional complexity to our application, reflected by the highlighted additions to the following code:

public class Course {
  // Attributes.
  // Pseudocode.
  private Collection offeredAs;      // a collection of Section object
                                     // "handles"
  private string courseName;
  private int courseNumber;
  private float creditHourValue;
  // Pseudocode.
  private Collection professors;   // a collection of Professor obj.
                                   // "handles"
  // etc.
}

public class Section {
  // Attributes.
  private Course represents;  // a "handle" on the related Course
                              // object
  private int sectionNo;
  private string dayOfWeek;
  private string timeOfDay;
  private string semester;
  private Professor taughtBy;  // a "handle" on the related Prof. object

  // etc.
}

public class Professor {
  // Pseudocode.
  private Collection coursesTaught;     // a collection of Course obj.
                                        // "handles"
  private Collection sectionsTaught;    // a collection of Section obj.
                                        // "handles"
  private string name;
  private string ssn;

  // etc.
}

By adding the redundant association, we now have extra work to do in terms of maintaining referential integrity. That is, if a different Professor is assigned to teach a particular Section, we have two links to update rather than one: the link between the Professor and the Section, and the link between the Professor and the related Course.

We'll talk more in Part Three of the book about the implications, from a coding standpoint, of making such trade-offs. The bottom line, however, is that deciding which associations to include, and which to eliminate as derivable from others, is similar to the decision of which web pages you might wish to create a bookmark for in your web browser: you bookmark those that you visit frequently, and type out the URL longhand, or alternatively traverse a chain of links, for those that you only occasionally need to access. The same is true for object linkages: the decisions of which to implement in code depends on which "communication pathways" through the application we're going to want to use most frequently. We'll get a much better sense of what these communication patterns are when we move on to modeling behaviors in Chapter 11.


Team LiB
Previous Section Next Section