munotes®

The Class Diagram

Get access to whole semester resourcesSemester Pass

Chapter Twenty-One

Syllabus topic Module 1, "System Modeling using UML: ... Class Diagram".

Pages 125 to 131 of 499

In one line

A class diagram shows the kinds of thing a system knows about, what each one holds, what it can do, and how they are related: the system's vocabulary, drawn as boxes and lines, true at every moment rather than describing any one event.

In the wording to use when asked: a class diagram is a UML structure diagram that shows classes with their attributes and operations, and the relationships between them: associations with their multiplicities and navigability, aggregation and composition, generalisation and dependency. It describes the static structure of a system, irrespective of time.

A class, drawn

A class is a rectangle with up to three compartments: its name, its attributes and its operations. Any compartment may be left out when it has nothing useful to say.

An attribute is written in UML's own grammar:

visibility / name : type [multiplicity] = default {modifiers}

Only the name is required. - stockLeft : int = 0 is a private attribute called stockLeft, an integer, starting at zero. A slash before the name marks a derived attribute, one that can be calculated from others. Where no multiplicity is written, an attribute holds exactly one value.

An operation is written visibility name(parameters) : return type, such as + takeStock(n : int) : boolean.

Visibility has four marks:

MarkVisibilityWho can use it
+publicanything that can see the class
-privateonly the class itself
#protectedthe class and its subclasses
~packageanything in the same package

An enumeration is a class of named values and nothing else, drawn with the keyword «enumeration» and its values listed, such as an order's status.

Relationships

RelationshipWhat it meansHow it is drawn
Associationobjects of one class are linked to objects of anothera solid line, optionally named, with a multiplicity at each end
Navigabilityfrom one end you can reach the otheran open arrowhead at the end that can be reached; a small x where it cannot
Aggregationa loose whole and part; the precise meaning is left to the modellera hollow diamond at the whole's end
Compositionthe part belongs to at most one whole at a time, and is deleted with ita filled diamond at the whole's end
Generalisationone class is a more specific kind of another, and inherits from ita solid line with a hollow triangle pointing at the general class
Dependencyone class uses another, so a change to the second may affect the firsta dashed arrow from the user to the used

Multiplicity, the part examiners ask about

A multiplicity at the end of an association says how many objects can be at that end: 1 exactly one, 0..1 none or one, 0.. or any number, 1..* at least one, 1..10 between one and ten.

munotes.in125

The Class Diagram

Read it from one class, across the line, to the number at the far end. On a line between User and Order with 1 at the User end and 0..* at the Order end: a user places any number of orders, and an order is placed by exactly one user.

One rule from the specification is worth knowing: where a diagram shows no multiplicity at the end of an association, no conclusion may be drawn about it. Absent is not the same as "one", so write them all.

Aggregation or composition

The test is two questions about the part: can it exist without the whole, and can it belong to two wholes at once? If both answers are no, it is composition. The specification's own definition: a composite part is included in at most one composite at a time, and if the composite is deleted, its parts are deleted with it.

Aggregation, the hollow diamond, is weaker, and the specification deliberately leaves its exact meaning to whoever uses it. Many teams therefore avoid it, and draw either a plain association or a composition. That is not a mistake; a hollow diamond whose meaning nobody can state is.

Domain model and design model

A class diagram can describe two different things, and a student should say which one theirs is.

A domain model describes the things of the problem itself: orders, menu items, users. It shows their attributes, their associations, and at most the few operations that carry the important rules. It says nothing about files, frameworks or the language.

A design model describes the classes or modules of the code: every operation with its parameters, visibility, the types of the language, often classes that exist only in the program, such as a controller or a data store.

MU's syllabus places the class diagram in the design phase, before building, so a student's class diagram is usually a domain model with its key operations. The worked team's is exactly that.

The worked diagram

A class diagram: User, composed of any number of Sessions by a filled diamond and joined to any number of Orders; Order composed of one to ten OrderItems by a filled diamond; each OrderItem pointing to one MenuItem; and three enumerations, Role, Category and Status, in the left column

Figure 21.1 The worked team's class diagram, drawn by PlantUML from the source below

@startuml class
!pragma layout smetana
top to bottom direction
hide empty members
hide circle

class User {
  id : int
  name : string
  email : string
  passwordHash : string
  role : Role
  isActive : boolean
}

class Session {
  id : string
  expiresAt : datetime
}

class Order {
  id : int
  pickupDate : date
  slot : string
  status : Status
  /totalPaise : int
  canMoveTo(to, by) : boolean
}

class OrderItem {
  quantity : int
  unitPricePaise : int
}

class MenuItem {
  id : int
  name : string
  category : Category
  pricePaise : int
  isVeg : boolean
  isAvailable : boolean
  stockLeft : int
  takeStock(n) : boolean
}

enum Role <<enumeration>> {
  student
  staff
  owner
}

enum Category <<enumeration>> {
  meals
  snacks
  drinks
  desserts
}

enum Status <<enumeration>> {
  placed
  preparing
  ready
  collected
  cancelled
  no_show
}

User "1" *-- "0..*" Session
User "1" -- "0..*" Order : places
Order "1" *-- "1..10" OrderItem
OrderItem "0..*" --> "1" MenuItem
Session -[hidden]down- Role
Role -[hidden]down- Category
Category -[hidden]down- Status
@enduml
munotes.in126

The Class Diagram

Reading it

User 1 to 0..* Session, a composition. A user may be signed in on several devices at once, a phone and a laptop, each a session. Each session belongs to exactly one user and cannot outlive them, so the diamond is filled; the database carries that out by deleting a user's sessions with the user (Chapter 24).

User 1 to 0..* Order, "places". Any number of orders, each placed by one user.

Order 1 to 1..10 OrderItem, a composition. An order item cannot exist without its order and belongs to only one, so the diamond is filled. The 1..10 comes from FR-7: at most 10 items in one order, so at most 10 lines. The rest of FR-7, no more than 5 of any one item and no more than 10 items in all, is a rule about quantities that no multiplicity can express; the SRS states it, and the code checks it.

OrderItem 0..* to 1 MenuItem, navigable one way. Each order item refers to exactly one menu item, and the arrow says an order item knows its menu item while a menu item keeps no list of the orders it is in. It is not a composition: the biryani exists whether or not anyone orders it.

Three enumerations. Role, Category and Status, each with exactly the values the database allows.

No generalisation. The use case diagram made the owner a specialisation of the counter staff. The class diagram does not make Owner a subclass of User. Students, counter staff and owners hold exactly the same data, a name, an email and so on, and differ only in what they may do. A difference in permissions is a value, role, not a new class. A subclass is for a kind of thing that holds different data or behaves differently.

Two operations. canMoveTo on Order and takeStock on MenuItem carry the two rules the whole system depends on: which status may follow which (FR-15), and never selling food that is not there (FR-9). Everything else is data.

One derived attribute. /totalPaise can be calculated from the order's items. The team still stores it, and stores each item's unit price in OrderItem although MenuItem has a price too, for the same reason: a price changed tomorrow must not change the total of an order placed today.

munotes.in127

The Class Diagram

The source, line by line

  • class User { ... } declares a class and lists its attributes; a line with brackets, such as canMoveTo(to, by) : boolean, is an operation.
  • enum Role <<enumeration>> { ... } declares an enumeration and shows UML's keyword above its name.
  • hide empty members leaves out a compartment with nothing in it, as the specification allows, and hide circle removes the small lettered circle PlantUML otherwise puts in every box, which is PlantUML's own decoration and not UML.
  • User "1" -- "0..*" Order : places is an association, with each multiplicity in quotes beside its class and the association's name after the colon.
  • Order "1" -- "1..10" OrderItem is a composition: the draws the filled diamond at the Order end. User "1" -- "0.." Session is another.
  • OrderItem "0..*" --> "1" MenuItem is an association navigable towards MenuItem.
  • The -[hidden]- lines draw nothing. They only ask the layout to stack the three enumerations in a column, which keeps the diagram narrow enough for a phone.

What a class diagram means for a JavaScript backend

The worked application has no JavaScript class called Order. Its backend reads rows from MySQL and hands them on as plain objects, and it keeps the rules in modules of functions. That is normal for a Node.js application, and it does not make the class diagram wrong: the diagram describes what the system knows and what it can do, and the code shows where each piece went when the team built it (Chapters 42 to 45).

An order, as the application sees it, has exactly the fields the store selects, each translated from its column name:

const ORDER_COLUMNS = `o.id, o.user_id AS userId,
  u.name AS studentName, o.pickup_date AS pickupDate,
  TIME_FORMAT(o.pickup_slot, '%H:%i') AS slot, o.status,
  o.total_paise AS totalPaise, o.created_at AS createdAt,
  o.updated_at AS updatedAt`;

Every translation follows the camelCase rule, except one: the column pickup_slot is read as slot. That is the one name that breaks the rule, and Chapter 19's advice applies to it: it is written down, and it is translated in this one place and nowhere else.

The two operations are two functions. Order.canMoveTo(to, by) is canMove(from, to, role), where from is the order's current status:

// Who may move an order from one status to another. The
// owner can do anything the counter staff can.
function canMove(from, to, role) {
  const mover = MOVES[from] && MOVES[from][to];
  if (!mover) return false;
  if (mover === 'student') return role === 'student';
  return role === 'staff' || role === 'owner';
}
munotes.in128

The Class Diagram

MenuItem.takeStock(n) is the store's takeStock, a single SQL statement that takes the stock only if enough is left:

    // Takes `quantity` from the stock only if that many are
    // left, in ONE statement, so two orders for the last
    // plate cannot both succeed. True if it was taken.
    async takeStock(conn, id, quantity) {
      const [result] = await conn.execute(
        `UPDATE menu_items
            SET stock_left = stock_left - ?
          WHERE id = ? AND is_available = TRUE
            AND stock_left >= ?`,
        [quantity, id, quantity]);
      return result.affectedRows === 1;
    },

And the derived total is calculated once, when the order is placed:

// lines: [{ quantity, pricePaise }]. Integers, so exact.
function orderTotal(lines) {
  return lines.reduce(
    (sum, line) => sum + line.quantity * line.pricePaise, 0);
}

If your project is written in Java, C# or PHP with classes, the mapping is even more direct: each class in the diagram becomes a class in the code, and each operation a method.

Checking it against the other diagrams

  • Against the ER diagram (Chapter 24). Every attribute of every class is a column of its table, and every association is a foreign key: userId in Order is the association to User, which is why the class diagram does not list it as an attribute. The one renamed column, pickup_slot, is explained above.
  • Against the sequence diagrams (Chapter 22). Every message sent to part of the system is an operation or a function it really has: taking the stock is takeStock.
  • Against the state machine (Chapter 23). The six values of Status are the six states, and canMoveTo allows exactly its five arrows.

Do this for your project

  1. Underline the nouns in your requirements and use cases; the important ones are your candidate classes.
  2. For each class, list what it must remember: those are its attributes, each with a type.
  3. Add only the operations that carry a business rule.
  4. Draw the associations, and write a multiplicity at both ends of every one. Read each aloud across the line.
  5. Choose composition only where a part cannot exist without its whole; avoid the hollow diamond unless you can say what it means.
  6. Use an enumeration for a fixed set of values, and a subclass only for a kind of thing that holds different data.
  7. Check every attribute against your database design, and write down any name that breaks your mapping rule.

Mistakes that cost marks

Foreign keys as attributes. userId : int inside Order says the same thing as the line to User, twice, and in the database's words rather than the model's.

Missing multiplicities. A line with no numbers says nothing about how many.

Multiplicities read the wrong way round. Read from one class across the line to the far end.

munotes.in129

The Class Diagram

Composition everywhere. A menu item is not part of an order; it exists without one.

A class for every screen or table, such as MenuPage or OrderForm, in a domain model.

Subclasses for roles, when the only difference between the "subclasses" is what they are allowed to do.

Operations with no rule behind them, such as a getter and a setter for every attribute. They add ink and no information.

Quick revision

  • A class: name, attributes, operations. Attribute: visibility / name : type [multiplicity] = default.
  • Visibility: + public, - private, # protected, ~ package. A slash marks a derived attribute.
  • Association with a multiplicity at each end, read across the line; an open arrowhead marks navigability.
  • Composition (filled diamond): the part is in at most one whole and dies with it. Aggregation (hollow diamond): looser, meaning left to the modeller.
  • Generalisation: hollow triangle to the general class. Dependency: dashed arrow from the user to the used.
  • A domain model describes the problem's things; a design model describes the code's classes.

Questions you must be able to answer

1. What does a class diagram show? The classes of a system, with their attributes and operations, and the relationships between them: associations with multiplicities, aggregation and composition, generalisation and dependency. It shows structure that is true at every moment, not what happens in any one scenario.

2. Explain the multiplicities on the association between User and Order in the worked diagram. There is a 1 at the User end and 0..* at the Order end. Reading across the line, a user places any number of orders, including none, and every order is placed by exactly one user.

3. What is the difference between aggregation and composition? Which is used between Order and OrderItem, and why? In composition the part belongs to at most one whole at a time and is deleted with it; aggregation is a looser whole-and-part whose exact meaning UML leaves to the modeller. Order and OrderItem use composition, because an order item cannot exist without its order and never belongs to two.

4. Why is there no Owner subclass of User? Because owners, counter staff and students hold the same data and differ only in what they are permitted to do. A difference in permission is represented by the value of the role attribute, an enumeration; a subclass would be needed only if an owner held different data or behaved differently as an object.

5. Why does OrderItem store a unit price when MenuItem already has a price? Because prices change. The unit price is copied into the order item when the order is placed, so that an order keeps the price the student agreed to, whatever the menu says later. The order's total is stored for the same reason, although it could be derived.

munotes.in130

The Class Diagram

6. The worked backend has no Order class. Is its class diagram still correct? Yes. The diagram is a domain model of what the system knows and does; the code keeps the data in plain objects and the rules in functions, and each operation in the diagram corresponds to a function in the code, such as canMoveTo to canMove and takeStock to the store's takeStock.

munotes.in131

The rest of this subject

These notes are cut from the University's printed syllabus. Open the syllabus itself for the same subject.

Issue
Done!