Post-notes on SDM Lab 1: Relating UML and Java, using Umple (updated 2018)
The exercises in this lab were essentially self-checking, so there are no
model solutions. If you're not sure whether something you did was OK or
not, post to Piazza about it and I'll gladly comment. Towards the end there
are questions designed to provoke you to think, rather than to get answered
precisely - feel free to post about those, too.
Things I remember saying (possibly not this year!) that might be useful to
anyone who had to miss the lab and is going through it afterwards (NB
that's no substitute for actually being there, so don't miss the lab unless
you have to!):
- Multiplicities in Umple class diagrams: put them in on the Umple text
side, there isn't a way to do that in the diagram.
- If Umple gets confused (spinning wheel that doesn't ever get replaced
by actual output) sometimes it helps to copy your Umple text code, shut
down the Umple Online tab, start a new one, and paste your Umple code back
into it.
- A class called System in a class diagram is a "bad smell" (technical
term!) because it suggests that you're heading towards having all
functionality in that class with the other classes relegated to being
simple data containers. The classes in your conceptual class diagram should
correspond to key concepts in the domain where the system will operate.
- Both attributes and navigable associations are properties of a class
in UML, and both will typically be implemented by attributes in the
eventual Java code. Don't represent the same information by both things.
Use associations where the type of the eventual attribute will be one of
the classes in the diagram (or a collection of them); use attributes where
the type of the eventual attribute will be a base type, or something from a
library that you're using rather than designing. One effect is: you
should never see the same name as both the name of a class in your class
diagram and the type of an attribute on your class diagram.
- This helps to obey the WRITE ONCE "rule". As we'll see a lot in this
course, any time you have two manually-created representations of the same
information, they have to be kept consistent, and that can be painful. So
you only do it when there's very good reason to. Otherwise, write each
piece of information once.
- Why does the Airline example have separate Role classes, rather than
just using Person and specialisations of it? If we had Passenger and
Employee specialising Person, then any actual object in the system of class
Person, say the one representing Perdita Stevens, could turn out to be an
instance of the subclass Employee or of the subclass Person, but not both
((begin nitpick) unless we're in a multi-classification
setting which is a dragonous region of UML we don't go into because it
doesn't correspond to anything you can implement in Java - and even then,
there'd still only be one object (end nitpick)). But we want to
allow for the case that I, Perdita Stevens, am both an airline pilot (say,
due to pilot the 9am flight Edinburgh to Glasgow on 23/9/18) and a
passenger (say, due to fly on the 6pm flight Glasgow to Edinburgh on
23/9/18), and we want to do this without duplicating the information that
the system keeps about me because I'm a Person. (We've only got a small
amount of information of that kind for now, but maybe there's lots; the
system may also need to be able to handle constraints like "the same person
can't be a crew member and a passenger on the very same flight" as briefly
discussed in the lab.) That's what the role concept is for. There's a
person object representing me, Perdita Stevens. If I ever fly on this
airline (maybe I know too much about its safety record to do so...) there's
a PassengerRole object that is linked to the Person object representing me.
This object knows about stuff like my frequent flyer status and my upcoming
bookings. Separately, there is an EmployeeRole object that is linked to the
Person object representing me. This object knows about stuff like my salary
and my record of employment.
Alternatively, it would have been possible
to combine all of this information into one class, but then the class would
have ended up not feeling very cohesive - we'd have found that it was doing
several, not very closely related, jobs. It would have felt unsatisfactory
because, for example, the 99% of objects in the system that represent
people who are only ever passengers would still have unused data nad
functionality pertaining to employees. So it's better design to separate
the functionality into several classes that are appropriately related. This
makes the system easier to understand and hence to maintain.
- I doubt if anyone finished the state diagram part of the lab in the
lab. As you do it (reinforcing the reading...), make sure you're clear on
the difference between protocol state diagrams (have transitions triggered
by events, possibly with conditions, do not have actions; are useful for
clients of the class being described) and behavioural state diagrams (can
have actions in addition to the elements that occur in protocol state
diagrams; are useful for implementors of the class being described).
Here's a pertinent question and answer from a previous presentation:
Q: Can you tell us how to best abstract a system so that no unnecessary
states are created so that the UML will not be overcomplicated
A: There's no single right answer to this, but I think a reasonable rule of
thumb would be: two fully-detailed states of an object should abstract into
different states of a state diagram if there is something qualitatively
different about the way the object behaves in the two states, so that the
reader of the diagram needs to be aware of that. The reader might be
someone intending to use the object (your client) or it might be someone
intending to implement the object's code - these readers have subtly
different requirements. Usually, the former will want a protocol state
diagram, the latter a behavioural state diagram. For example, (see the
first state diagram video) if an object should be initialised before it
makes sense to send it the doIt message, then you can document that using a
state diagram showing that the Uninitialised state is the first state
reached after object creation, and then the initialise() message causes the
object to transition to the Ready state, which has a self-transition caused
by receiving doIt().
This page is maintained by
Perdita Stevens (
perdita@inf.ed.ac.uk
)