You get a bonus - 1 coin for daily activity. Now you have 1 coin

3.2. Relationships among objects

Lecture



Kinds of relationships

Objects by themselves are of no interest whatsoever: a system is realized only in the process of interaction among objects. In Ingalls's words: "Instead of a bit-grinding processor plundering data structures, we have a community of well-mannered objects that politely ask each other for services" [13]. An airplane is, by definition, "a collection of parts, each of which by its nature tends to fall to the ground, but which by joint continuous effort overcome this tendency" [14]. It flies only thanks to the coordinated efforts of its components.

The relationship of any two objects is based on the assumptions that one holds about the other: about the operations that can be performed and about the expected behavior. Of special interest for object-oriented analysis and design are two kinds of hierarchical relationships among objects:

  • links;
  • aggregation.

Seidewitz and Stark called these two kinds of relationships seniority relationships and "parent/child" relationships, respectively [15].

Links

Semantics. We borrow the notion of a link from Rumbaugh, who defines it as a "physical or conceptual connection between objects" [16]. An object collaborates with other objects through the links connecting it to them. In other words, a link is a specific association through which a client requests a service from a server object or through which one object finds a path to another.

Figure 3-2 shows several different links. They are marked by lines and denote, as it were, the paths along which messages travel. The messages themselves are shown by arrows (corresponding to their direction) and labeled with the name of the operation. In the figure the object aController is linked to two objects of the class DisplayItem (the objects a and b). In turn, both are probably linked to aView, but we were interested in only one of these links. Only along a link can one object send a message to another.

The link between objects and the passing of messages is usually one-way (as in the figure; although technically it may also be mutual). As we will see in Chapter 5, such a division of rights and duties is typical of well-structured object systems [In fact, the organization of objects shown in Figure 3-2 is encountered so often that it may be considered a design pattern. In Smalltalk a similar mechanism is known as MVC, model/view/controller. As we will see in the next chapter, well-structured systems have many such recognizable patterns]. Note also that although the message being passed is initiated by the client (in this case aController), data are transferred in both directions. For example, when aController invokes the operation move to send data to the object a, the data are transferred from the client to the server, but when the operation isUnder is performed on the object b, the result is transferred from the server to the client.

Participating in a link, an object can play one of the following three roles:

® Actor [Actor means a doer, a performer. And a performer of roles is precisely an actor. — Ed. note]. An object can act upon other objects, but is itself never acted upon by other objects; in a certain sense this corresponds to the notion of an active object.

3.2. Relationships among objects

Figure 3-2. Links.

® Server. An object can only be acted upon by other objects, but it never acts in the role of an acting object.

® Agent. Such an object can act in both an active and a passive role; as a rule, an agent object is created to perform operations on behalf of some actor object or agent.

In Figure 3-2 the object aController acts as an actor, the object a as an agent, and the object aView as a server.

Example. Many industrial processes require continuous change of temperature. It is necessary to raise the temperature to a given value, hold it for a given time, and lower it back to normal. The temperature change profile differs for different processes; a telescope mirror must be cooled very slowly, and steel being hardened very quickly.

The heating abstraction has a sufficiently well-defined behavior, which gives us the right to describe such a class. First let us define a type whose value specifies the elapsed time in minutes.

// Number of elapsed minutes
typedef unsigned int Minute;

Now let us describe the class TemperatureRamp itself, which in meaning specifies temperature as a function of time:

class TemperatureRamp {
public:

TemperatureRamp();
virtual ~TemperatureRamp();
virtual void clear();
virtual void bind (Temperature, Minute);
Temperature TemperatureAt (Minute);

protected:
...
};

Keeping to our style, we have declared some of the operations virtual, since we expect that this class will have subclasses.

In fact, in terms of behavior we need something more than simply the dependence of temperature on time. Suppose, for example, it is known that at minute 60 a temperature of 250ЂF must be reached, and at minute 180 a temperature of 150ЂF. The question is, what should it be at minute 120? This requires linear interpolation, so the behavior required of the abstraction becomes more complicated.

At the same time, we do not require of this abstraction the control of the heater that maintains the required profile. We prefer a separation of concerns in which the needed behavior is achieved by the interaction of three objects: an instance of TemperatureRamp, the heater, and the controller. The class TemperatureController can be defined as follows:

class TemperatureController {
public:

TemperatureController(Location);
~TemperatureController();
void process(const TemperatureRamp&);
Minute schedule(const TemperatureRamp&) const;

private:
...
};

The type Location was defined in Chapter 2. Note that we do not expect inheritance from this class and therefore do not declare any virtual functions in it.

The operation process provides the basic behavior of this abstraction; its purpose is to convey the temperature change schedule to the heater installed in a specific place. For example, let us declare:

TemperatureRamp growingRamp;
TemperatureController rampController(7);

Now let us specify a pair of points and load the plan into the controller::

growingRamp.bind (250, 60);
growingRamp.bind(150, 180);
rampController.process(growingRamp);

In this example rampController is the agent responsible for carrying out the temperature plan; it uses the object growingRamp as a server. This link is manifested at least in the fact that rampController explicitly receives growingRamp as a parameter of one of its operations.

One remark about our style. At first glance it may seem that our abstractions are merely object wrappers for elements obtained as a result of ordinary functional decomposition. The example of the operation schedule shows that this is not so. Objects of the class TemperatureController have enough intelligence to determine the schedule for specific profiles, and we include this operation as additional behavior of our abstraction. In some energy-intensive technologies (for example, the smelting of metals) substantial gains can be made if one takes into account the cooling of the installation and the heat remaining from the previous melt. Since the operation schedule exists, a client can ask the object TemperatureController to recommend the optimal moment for starting the next heating.

Visibility. Suppose there are two objects A and B and a link between them. In order for A to be able to send a message to B, B must in some sense be visible to A. We may not worry about this at the analysis stage, but when it comes to implementing the system, we must ensure the visibility of linked objects.

In the previous example the object rampController sees the object growingRamp, since both of them are declared in the same scope and because growingRamp is passed to the object rampController as a parameter. In principle there are the following four ways to provide visibility.

  • The server is global with respect to the client.
  • The server (or a pointer to it) is passed to the client as a parameter of an operation.
  • The server is a part of the client.
  • The server is locally created by the client in the course of performing some operation.

Which of these ways to choose depends on design tactics.

Synchronization. When one object sends a message over a link to another object connected to it, the two are said to synchronize. In a strictly sequential application, synchronizing objects consists simply of invoking a method (see the sidebar below). In a multithreaded system, however, objects require a more sophisticated message-passing scheme in order to resolve the mutual exclusion problems typical of concurrent systems. Active objects execute as threads in their own right, so the presence of other active objects usually does not affect them. If an active object has a link to a passive one, the following three approaches to synchronization are possible:

  • Sequential - the semantics of the passive object are guaranteed only in the presence of a single active process.
  • Guarded - the semantics of the passive object are guaranteed in the presence of multiple threads of control, but the active clients must collaborate to achieve mutual exclusion.
  • Synchronous - the semantics of the passive object are guaranteed in the presence of multiple threads of control; the server itself guarantees mutual exclusion.

All the objects described in this chapter have been sequential. In Chapter 9 we will examine the remaining variants in more detail.

Aggregation

Semantics. Whereas links denote peer-to-peer or "client/server" relationships among objects, aggregation describes whole/part relationships, which give rise to a corresponding hierarchy of objects: starting from the whole (the aggregate), we can reach its parts (its attributes). In this sense, aggregation is a specialized special case of association. In Figure 3-3, the object rampController has a link to the object growingRamp and an attribute h of the class Heater. In this case, rampController is the whole, and h is one of its parts. In other words, h is part of the state of rampController. Given rampController, it is possible to find the corresponding heater. However, given h one cannot find the object that contains it (also called its container), unless information about that container happens to be part of the state of h.

3.2. Relationships among objects

Figure 3-3. Aggregation.

Aggregation may, but need not, denote physical containment of one object within another. An airplane consists of wings, engines, landing gear, and other parts. On the other hand, the relationship between a shareholder and his shares is an aggregation that does not involve physical containment. A shareholder exclusively owns his shares, but they are not physically part of him. This is unquestionably an aggregation relationship, yet one that is conceptual rather than physical in nature.

In choosing between a link and an aggregation, keep the following in mind. Aggregation is sometimes preferable because it allows the parts to be hidden within the whole. Sometimes, on the contrary, links are preferable because they are weaker and less constraining. In making the decision, all of this must be weighed.

An object that is an attribute of another object (the aggregate) has a link to its aggregate. Through this link the aggregate can send it messages.

Example. Let us add to the specification of the class TemperatureController a declaration of a heater:

Heater h;

After this, every TemperatureController object will have its own heater. Given our definition of the class Heater in the previous chapter, we must initialize the heater when a new controller is created, since that class provides no default constructor. We could define the constructor of the class TemperatureController as follows:

TemperatureController::TemperatureController(Location 1) : h(1) {}

Comments

To leave a comment

If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Lectures and tutorial on "Object Oriented Analysis and Design"

Terms: Object Oriented Analysis and Design