4 THE CLASS MODEL  27/10/97  4.4 Relationships between classes

4.4.2 Generalisation

Another possible relationship between classes is generalisation. For example, Customer is a generalisation of Personal Customer because conceptually, every Personal Customer is a Customer. Everything that is true of every Customer is a fortiori true of every Personal Customer. So if some part of our system works on an arbitrary Customer, it ought to work on an arbitrary Personal Customer too, since every Personal Customer is a Customer. On the other hand, there may be things that don’t make sense for every Customer, but only for Personal Customers. Personal Customer is more specialised than Customer; or Customer is a generalisation of Personal Customer.

In terms of interfaces, an object of class PersonalCustomer should conform to the interface given by Customer: if some message is acceptable to any Customer, it is of course fine to send that message to a PersonalCustomer. PersonalCustomer may understand other, specialised messages as well – that is, its interface may be strictly broader than Customer’s.

As I’ve implied, to say that there’s a generalisation relationship between classes is to make a strong, though informal, statement about the way their objects behave: an object of a specialised class is substitutable in any context which expects a(n arbitrary) member of the more general class. In particular, even though what an object does on receipt of a message is encapsulated, there had better be no conceptual gulf between what objects of the two classes do on receipt of the same message. Their behaviour doesn’t have to be identical, but it must be similar enough not to make code that works with an object of a general class fail to work with an object of a specialised class.

Using English to check whether a generalisation exists Class Foo is probably a generalisation of class Bar if it’s true that every Foo is a Bar. (Often we just talk about “is a” relationships – a Foo is a Bar – but then it’s possible to come unstuck. For example (from Fowler p91), you might casually say “a Border Collie is a Breed” and conclude that Breed is a generalisation of BorderCollie, which is rubbish. Try out “every Border Collie is a Breed” which is more obvious rubbish. The problem is actually, I think, that the English “a Border Collie is a Breed” is wrong to start with: it should have been “Border Collie is a Breed”. But putting in “every” may help. I don’t personally find Fowler’s suggestion that you consider “Border Collies are kinds of Breeds” helpful, but you may.

Implementing generalisation: inheritance One way (not the only way) to implement a generalisation is by inheritance. Whereas generalisation is a conceptual relationship between classes, inheritance is an implementation relationship. Instead of duplicating the definition of Customer, and possibly adding to it, to define PersonalCustomer – which would be possible, and there would still be a generalisation between Customer and PersonalCustomer – we often choose to use the facility provided by OOPLs of inheritance to define PersonalCustomer in terms of Customer.

If we define class PersonalCustomer by inheritance from class Customer, we only have to write code for the new parts of PersonalCustomer’s interface; for example, we have to add operations to react to any messages which can be received by a PersonalCustomer but not by an arbitrary Customer.

More interestingly, because in object orientation knowledge of which code an object executes when it receives a message is encapsulated, it is possible for class PersonalCustomer to implement different behaviour on receipt of some message from what Customer implements. That is, we can override some of Customer’s behaviour in PersonalCustomer.

Terminology We say that

• PersonalCustomer inherits from Customer

• PersonalCustomer is a subclass of Customer

• Customer is a superclass of PersonalCustomer

Do we say that an object of class PersonalCustomer belongs to class Customer? We should, if we are thinking about classes as sets of objects. When I talk about “an object of class Customer” I will certainly include the objects which also belong to class PersonalCustomer. However, it’s just too convenient to be able to talk about “the class of this object” as though the object only belonged to one class. When I say this, I will mean the most specialised class to which the object belongs. This means that it remains true that an object’s behaviour is determined by its class!

In UML, we show generalisation like this:

Generalisation

Slide 34

4.4.3 Aggregation: “is part of”

An aggregation relationship between two classes is a particular kind of association, which shows that an object of one class (B, say) is a part of an object of the other (say A). Usually, but not always, the object of class B lives and dies with the object of class A; if an object of class A is deleted, then its component part of class B must also be deleted.

(In fact, UML 1.1 also defines an even more specific term, composition, to represent the kind of aggregation in which the “Usually” above applies, but in this course we will not discuss that.)

Here’s an example:

4 THE CLASS MODEL  27/10/97  4.5 Development of class model

An aggregation relationship

Slide 35

This is part of an example from the UML 1.1 documentation, reproduced in Fowler; but even here, some designers might choose to show this as a plain association, rather than as an aggregation. The reason why it isn’t totally clear that this should be aggregation is that a Point may play several roles in the system, and the “Usually” condition above will probably not be satisfied; for example, a point may be a vertex of several polygons.

In general, how do you tell whether aggregation is appropriate or whether you should just show an association? There’s no hard and fast answer; different designers will make different decisions. Rough guidelines:

• If an object of class B must be created every time an object of class A is created, and must be deleted if and only if the object of class A is deleted, consider using aggregation.

• If class A is the only class in the system which has a relationship with class B – so that in particular, the existence of an object of class B is not going to be exposed in the interface of class A – consider using aggregation. If you find yourself using aggregation when this condition isn’t satisfied, think very hard about whether you really mean it.

If in doubt, use plain association. A plain association will always be correct when an aggregation is: the purpose of aggregation is to be more specific about the kind of association involved.

We don’t normally name an aggregation relationship, because it is assumed that the relationship is “is part of”. Multiplicities may still be useful: in the example, I showed that each polygon must contain at least 3 points. I didn’t specify the multiplicity at the Polygon end. If I had shown a 1 there, for example, it would have represented the assertion that each point object in the system is a vertext of exactly one polygon object in the system.

4.5 Development of class model

The class model is one of the first UML models you start to create, and it will be developed thoughout the project, changing its role as the development proceeds.

4 THE CLASS MODEL  27/10/97  4.6 A simple example

At the beginning, in the Inception and (early) Elaboration phase, or if you like in requirements capture and analysis, the class model records the understanding we gain about the problem domain. We try not to make premature design decisions. Therefore, for example,

• we do not consider in which direction(s) an association is navigable: that is, which object knows about (has a pointer to) which other object. We just record that there’s some connection, association.

• when we record an attribute, say name on Customer, we do not imply that the class Customer will necessarily have an attribute called name, let alone a public one – we just mean to represent that customers have names

• if we identify aggregation and composition relationships at all (and some designers prefer not to, at this stage) we are describing a notional connection between the objects, which may or may not turn into an implementational relationship.

That is, in the initial class diagram is drawn at a conceptual level. As development proceeds and we make more design decisions, we make it more concrete and add more information, so that by the end, we have a diagram from which (some) code can be generated. We won’t go into details here about this, but the process is important.

4.6 A simple example

Example

The CS4 administration system should be able to report on any student: for example, whether the student is graduating or non graduating, what modules the student is taking, what honours course a graduating student is registered for, which lecturer is the student’s DoS.

It also acts as a repository of information on modules: who lectures them, what degree course they’re part of, which students are taking them.

Draw a conceptual level class model to represent this information. Include multiplicities, but don’t worry about attributes and operations.

Slide 36