Object Oriented Programming - Collaborations and Relationships

From SwinBrain

A Room may collaborate with an Exit to move a Player to a new location
An object oriented program divides its functionality across a number of Roles. In order for this arrangement to be able to achieve the required result these Roles need to be able to work together, in other words the objects in your solution need to be able to collaborate. Collaboration is achieved by objects sending messages to each other, requesting information or actions.

Contents

Planning Collaborations

As you discover Roles and Responsibilities for your program you will also need to plan how your objects will collaborate. Planning these interaction collaborations will help you discover additional roles and responsibilities you may not have previously thought of.

When planning collaboration you need to think about the objects your program has access to and the objects or information that needs to be used or altered. To achieve this new functionality you need to map a path from the objects you have to the objects you want to interact with, introducing responsibilities to allow these objects to pass on the messages that you need performed. For Example, in a Maze game you may want a Player to leave their current location heading in a given direction. This may be implemented with the following interactions:

  1. The Program tells the GameController "Move North"
  2. The GameController tells the Player to "leave heading north"
  3. The Player tells its current location to "move me north"
  4. The Room asks each of its exits "do you head north?". If the exit responds "Yes"...
    1. Tell the Exit "Move this player"
    2. The Exit tells the Player "You are now in this room" using its destination Room

This sequence of interactions starts with the program knowing only about the GameController and telling. The GameController knows about the Player, but not the Room the player is in, so it can ask the Player to leave heading in a given direction, etc. This makes it possible for each object just to know about objects that are relevant to them, and complex results can be achieved by objects communicating with each other.

Relationships

Collaboration is a central concept in object design, and for collaborations to be possible objects need to be know about each other. When designing collaborations we can think of these relationships as falling into one of three categories: dependency, association and inheritance.

A Class Diagram showing the different kinds of relationships.


Dependency

This kind of relationship can be thought of as a "uses" relationship and represents a temporary relationship between Roles in which one Role uses an object or objects of another Role.

There is one dependency relationship in the Drawing Example. The Drawing Controller alters Shape objects. This relationship is needed to realise the Change Size and Change Color responsibilities of the Drawing Controller. In this case the Drawing Controller asks its Drawing for the Selected Shape, which it then tells to change its color or size. Once the interaction is complete the Drawing Controller can forget about the Shape, the relationship is over.

The chief characteristic of a dependency relationship is that the relationship is temporary. In the example above, the Drawing Controller only knows about the Shape after having asked the Drawing for the selected shape and then forgets about it once the interaction is complete.

In a UML Class Diagram a dependency relationship is drawn with a dashed arrow that points to the class that is used. In the Drawing example a dashed arrow with the descriptive text Alters can be drawn from the Drawing Controller to the Shape.

In code a dependency relationship means the relationship exists as local variables only. With the example, the DrawingController's ChangeSize method would have a Shape local variable that it uses to refer to the object it is interacting with. These relationships can, therefore, be initialised with their respective objects in one of three ways:

  • A new object could be created.
  • An known object could be asked for the required object (as is the case in the example).
  • An object could be passed in as a parameter.

Association

Unlike a dependency, an association is a permanent relationship: the object knows the object or objects it is associated with. The association relationship can be though of as "has-a", as in "The DrawingController has-a Drawing", "The Drawing has 0 or 1 selected Shapes", or "A Drawing has-a number of Shapes". This means that the object can collaborate with the objects it is associated with whenever it needs to. In code this is implemented in the same way as any other knows style responsibility: a field is used to store a reference to the associated object, or a collection object used to contain objects of the indicated type.

For example, in the Drawing Example the DrawingController is associated with a single Drawing object. This means that in any of the DrawingController has a field storing a reference to a Drawing object, and that the DrawingController's methods are able to use this field to collaborate with the Drawing object as required.

Its important to note that while this is a permanent relationship between Roles, it is possible to use this so that individual objects may be related to others. In this case it is possible that the objects knows it doesn't have any object for a given relationship some of the time. This makes it possible to be associated with 0 or more objects of a given type. In the Drawing Example the Drawing class has a selected shape. This is a permanent relationship, you can ask any Drawing for its selected shape at any time. However, some of the time the Drawing object will not have a selected shape. Its still something the object knows, making it an appropriate association with 0 or 1 Shape objects.

Conceptually there are actually three variations of association. The one discussed above is the standard association, and is suitable in many cases. The other two forms of association are aggregation and composite aggregation. As you can tell from the name they both relate to aggregation: which relates to containment and whole/part relationships.

  • Aggregation: The whole is made up of parts, but the parts can be shared with other objects.
  • Composite Aggregation: The whole is made up of parts, and the lifetime of these parts is controlled by the lifetime of the whole. (i.e. when the whole is destroyed, so are the parts).

Associations are drawn on UML class diagrams in the following ways:

  • Association = a solid line between the two classes involved. If there are no arrow heads it indicates a bidirectional association (they know about each other). An optional arrow head can be used to indicate a unidirectional relationship (one knows of the other).
  • Aggregation = a solid line with a hollow diamond on the whole side of the relationship. This is shown in the Drawing Example's Class Diagram between the Drawing and Shape classes.
  • Composite Aggregation = same as aggregation, but with a filled rather than hollow diamond.

Inheritance

The association and dependency relationships are used to denote "uses-a" and "has-a" relationships that exist between objects playing these roles. Unlike these relationships, the inheritance relationship denotes a sub type (specialisation) between the Roles involved: showing that one Role is a specialisation of another Role. Inheritance can be thought of as is-a kind of, as in a Rectangle is a kind of Shape.

In the Drawing Example the Line, Rectangle, and Ellipse are all kinds of Shapes. This indicates that Line, Rectangle, or Ellipse objects all inherit the features of the Shape class, and that objects of these classes can be used in contexts where a Shape is required (see Inheritance).

In a UML class diagram inheritance is drawn using a solid line with a open triangle pointing from the derived class to the base class.