Part IV

GRASP: Assigning Responsibilities

Once you know what the system must do, you still have to decide which software object does what. GRASP gives you nine named principles for making that decision methodically, and in this subject every design answer is expected to name them.

  • You willtell doing from knowing responsibilities, and see why drawing a message is assigning one.
  • You willknow the problem, solution, benefits and contraindications of all nine GRASP principles.
  • You willbuild a design sequence diagram for a system operation and justify every message by a principle.
  • You willpick the right principle in a multiple-choice question and write justifications that earn marks.
4.1

Object Design, Responsibilities and Patterns

Analysis (Parts I and II) told you what the system must do. Object design answers the next question: which software object does what? This section sets the scene: what object design starts from, what a "responsibility" is, and why naming design ideas as patterns helps.

How this is examined

Question 1 of the exam has multiple-choice items of the form "pick the pattern that best fits this design problem". GRASP names appear both as the right answers and as distractors (Controller, Information Expert, Low Cohesion, Polymorphism, Indirection, …).

Beyond that, every design question, whether it asks for a design sequence diagram, a design class diagram or "describe this class", expects you to justify who does what by naming the principle.

Where object design starts

Object design does not start from a blank page. Each analysis artefact you met earlier hands the designer something specific, and the output for one scenario is called a use case realisation: the UP term for how one use case scenario is carried out in the Design Model by collaborating objects.

Use case text the behaviour the objects must realise System sequence diagram (SSD) system operations: each one goes to a controller Operation contracts postconditions the design must make true Domain model names, attributes and associations (LRG) Supplementary spec and glossary non-functional goals, formats, validation rules Object design which object does what? guided by GRASP Use case realisation design sequence (or communication) diagrams, one per system operation, plus a design class diagram (DCD)
What goes in, what comes out. Notice the SSD's role: every system operation (makeNewSale, enterItem, …) becomes the first message into the domain layer, and some object must receive it. That object is the controller (4.5). You draw one interaction diagram per system operation.
Definition · Low representational gap (LRG)

Name and structure the software classes after the domain concepts (Board, Square, not AB324), so the code mirrors how people think about the domain. LRG is why the domain model is the first place you look for candidate classes.

Even so, a design is not a one-to-one simulation of the real world. You may add classes that are not in the domain model, drop domain classes, and use different multiplicities. The Monopoly design below does all three kinds of thing; NextGen POS does the third, because the software Store creates just one Register.

Domain model: real-world concepts Design classes: software (iteration 2) Player Piece owns ▸ 11 Die rolls ▾ 2 Square is on ▾ 0..81 Board contains ▴ 401 Player Cup added: Pure Fabrication cup1 Die dice2..* Square location1 Board squares40 Piece dropped
Inspired by the domain, not copied from it. On the left, plain association lines (a domain model has no arrows or methods). On the right, the software classes keep the domain names (low gap) but add a Cup that no Monopoly player would list as a concept, drop Piece because Player can hold its own location, and turn associations into navigable arrows. Why each change was made is explained in 4.7 and 4.6.

The design also follows Model-View Separation: domain objects do not do output, and UI objects contain no application logic. So when the use case says "System displays total", the design only has to make sure that some object knows the total. Showing it is the UI's job.

Larman's underlying point is that UML is only notation. The real design tool is a mind trained in design principles, and GRASP gives those principles names.

Responsibilities: doing and knowing exam

Definition · Responsibility

The UML defines a responsibility as "a contract or obligation of a classifier". Informally, it is what an object is obliged to do or to know because of its role. That gives two kinds.

Responsibility a contract or obligation of a classifier Doing • doing something itself (create, calculate) • initiating action in other objects • controlling and coordinating other objects e.g.Sale creates SalesLineItems Knowing • its own private, encapsulated data • about related objects • things it can derive or calculate e.g.Sale knows its total
Two kinds of obligation. Knowing responsibilities usually come straight from the domain model's attributes and associations: the domain Sale has a time, so the software Sale knows its time (that is LRG at work).

A responsibility is not a method. It is an abstraction, and methods fulfil it. Its size varies a lot: "create a Sale" is one method, while "provide access to relational databases" might take a subsystem of hundreds of classes.

A method can fulfil a responsibility alone or by sending messages to other objects, which is called collaboration. For example, Sale.getTotal fulfils "know the sale total" by asking each SalesLineItem for its subtotal.

Responsibility-Driven Design (RDD)

Intuition · RDD

RDD is a metaphor: treat software objects like people who have responsibilities and collaborate with others to get work done. An OO design is then a community of collaborating, responsible objects.

In practice you decide responsibilities while drawing interaction diagrams (and while coding). There is no separate "assign responsibilities" document: every arrow you draw is a decision about who does what, and the design class diagram then records those decisions in its method compartments.

Drawing the message: the decision The DCD: the record :Sale makePayment(cash) create(cash) by Creator p : Payment Sale -isComplete: Boolean +makePayment(cash: Money) Payment payment1
The arrow is the decision. Drawing makePayment arriving at :Sale, and :Sale sending create to :Payment, is the decision "Sale is responsible for creating Payments". The DCD (right) records it as a method of Sale and a navigable association to Payment. Violet labels like by Creator name the GRASP principle behind a message; this page uses that colour for them throughout.

What a pattern is

Experienced designers keep reusing the same handful of good ideas. Writing those ideas down in a standard form, with a name, lets beginners use them too.

Definition · Pattern

A pattern is a named, well-known problem/solution pair that can be applied in new contexts, ideally with advice on how to apply it and a discussion of its trade-offs (Larman ch. 17). The lecture's own definition: "a recurring successful application of expertise in a particular domain".

The name matters. It helps you hold the idea in memory, and it lets you describe a complex design in one sentence, such as "put a Facade over the persistence subsystem and use an Abstract Factory for the mappers".

The lecture lists five advantages of patterns:

  • they capture expertise in a standard form that non-experts can use;
  • that expertise is easy to re-use;
  • they improve understandability;
  • they give practitioners a common vocabulary;
  • you can build new solutions by modifying existing patterns.

Because patterns codify old, proven knowledge, "new pattern" is an oxymoron. GRASP likewise introduces no new ideas: it names principles experts already use.

Larman's pattern format describes every pattern under the same headings. For each GRASP principle, the three you must be able to state are the Problem, the Solution and the Contraindications.

Learn this

Problem

The design question the pattern answers, e.g. "Who should create an A?"
Learn this

Solution

The advice: what to do, e.g. "B creates A if B contains A".
Learn this

Contraindications

When not to use it, because it would make things worse.
Also given

Name · Example · Discussion · Benefits · Related

A handle, a worked case, subtleties, what you gain, and neighbouring patterns.

GoF refers to the 23 patterns of Design Patterns by Gamma, Helm, Johnson and Vlissides (the "Gang of Four", 1994), such as Adapter and Strategy (Part VI). The pattern idea itself came from Christopher Alexander's building architecture and was brought to software by Kent Beck and Ward Cunningham.

GRASP: the nine at a glance exam

GRASP

General Responsibility Assignment Software Patterns: nine patterns, or principles, for assigning responsibilities to objects so that design reasoning is methodical, rational and explainable. Whether you call each one a pattern or a principle does not matter ("one person's pattern is another person's primitive building block").

Larman calls GRASP a learning aid, but in this subject you are marked on using the names correctly.

The nine do not all do the same job. One is the root goal, two are the yardsticks you measure designs with, three tell you who gets a particular kind of responsibility, and three are mechanisms for reaching the goals.

Root goalwhat everything serves Evaluative goalsuse to compare designs Assignment ruleswho gets a responsibility Mechanismsways to reach the goals Protected Variationsstable interfaces around change Low Couplingfew, stable dependencies High Cohesionfocused, related responsibilities Information Expertthe default rule Creatorwho creates an A? Controllerwho receives a system event? Polymorphismbehaviour varies by type Pure Fabricationinvent a non-domain class Indirectionput an intermediary in between
Four jobs, nine principles. Information Expert is the rule you try first; Creator and Controller handle two specific kinds of responsibility; Low Coupling and High Cohesion are how you judge the result; Polymorphism, Pure Fabrication and Indirection are tools; Protected Variations is what it is all for. How they feed into one another is drawn in 4.9.
PrincipleProblem it answersSolution (in brief)Role
Information ExpertWhat is a general principle for assigning a responsibility?Give it to the class that has the information needed to fulfil itDefault assignment rule
CreatorWho creates an instance of A?Class B, if B contains/compositely aggregates, records, closely uses, or has the initialising data for AAssigning creation
ControllerWhat is the first object beyond the UI layer that receives and coordinates a system operation?An object representing the whole system, a root object, a device or a subsystem (façade controller), or the use case scenario (use-case/session controller)Assigning system events
Low CouplingHow to support low dependency, low change impact and more reuse?Assign so that (unnecessary) coupling stays low. Use it to evaluate alternativesEvaluative goal
High CohesionHow to keep objects focused, understandable and manageable (and, as a side effect, support Low Coupling)?Assign so that cohesion stays high. Use it to evaluate alternativesEvaluative goal
PolymorphismHow to handle alternatives based on type? How to make pluggable components?Give the varying behaviour, as polymorphic operations, to the types that vary. Don't test for typeMechanism
Pure FabricationWho gets a responsibility when Expert (etc.) would hurt cohesion or coupling?Invent an artificial, non-domain class with a highly cohesive set of responsibilitiesMechanism
IndirectionWhere to put a responsibility so that two things are not directly coupled?Give it to an intermediate object that mediates between themMechanism
Protected VariationsHow to design elements so that variation or instability in them does not harm other elements?Identify points of predicted variation or instability; wrap them in a stable interfaceRoot goal
Check yourselfClassify each as a doing or a knowing responsibility: (a) Sale knows its time; (b) Sale creates SalesLineItems; (c) SalesLineItem knows its ProductDescription; (d) Register coordinates the enterItem system operation; (e) Register asks Sale to make a line item.

(a) knowing: its own encapsulated data. (b) doing: doing something itself (creating an object). (c) knowing: knowing about a related object. (d) doing: controlling and coordinating activities in other objects. (e) doing: initiating action in another object.

Check yourselfA classmate says "a responsibility is just a method". What is wrong with that, and when do responsibilities actually get decided?

A responsibility is an abstraction; methods fulfil it, alone or by collaborating with other objects. Its granularity varies: "create a Sale" may be one method, "provide access to relational databases" may be a whole subsystem. Responsibilities are decided while drawing interaction diagrams (and while coding): drawing a message to an object assigns that responsibility, and the DCD records it.

Check yourselfWhich two GRASP principles are evaluative, and which is the root goal? Why might an MCQ list "Low Cohesion" as an option?

Low Coupling and High Cohesion are evaluative: you use them to compare alternative designs. Protected Variations is the root goal. "Low Cohesion" names the problem rather than the principle; when a question describes a class that does too many unrelated things and asks what is wrong, "Low Cohesion" is the right label for the problem.

In short
  • Object design turns analysis artefacts into a use case realisation: one interaction diagram per system operation, plus a DCD.
  • Software classes take domain names (LRG), but the design may add, drop and reshape classes.
  • Responsibilities are doing or knowing; drawing a message assigns one.
  • GRASP names nine principles: one root goal (PV), two evaluative goals (LC, HC), three assignment rules (Expert, Creator, Controller) and three mechanisms (Polymorphism, Pure Fabrication, Indirection).
4.2

Creator exam

Creating objects is one of the most common things an OO program does. If every class could create anything, you would get coupling everywhere. Creator gives a consistent rule for who creates, and the rule is chosen so that creating adds no new coupling.

Problem

Who should be responsible for creating a new instance of some class A?

Solution

Give class B the job of creating A if any of these hold (the more, the better):

  1. B contains or compositely aggregates A;
  2. B records A;
  3. B closely uses A;
  4. B has the initialising data for A (then B is the Expert for creating A).

If several classes qualify, prefer the one that contains or aggregates A.

How to apply it

B and A are software classes. Look first for existing design classes that fit the role of B. If there are none yet, borrow from the domain model (LRG) and mirror its containment in the design.

The reason it works is simple: the chosen creator is normally connected to the new object anyway, because it contains, records or uses it. Making it the creator therefore adds no new coupling.

The lecture works through the checklist for Monopoly's Square, which makes a good template for exam answers.

Creator criterion (A = Square) Board Piece 1. contains or compositely aggregates A ✓– 2. records A –– 3. closely uses A ✓✓ 4. has the initialising data for A –– Board creates the Squares: two criteria, including the preferred one ("contains").
Run the checklist, then apply the tie-break. Board and Piece both "closely use" squares, but only Board also contains them, and containment is the preferred criterion.

In the diagrams, Creator shows up twice: as a create message in the sequence diagram (the dynamic view) and, often, as composite aggregation in the DCD (the static view).

Dynamic view: create messages Static view: composition in the DCD :MonopolyGame create() by Creator :Board loop [i = 1 to 40] create(name) by Creator :Square Board +getSquare(name: String): Square squares40 Square -name: String
One decision, two views. The game creates the board (it contains it); the board creates its 40 squares (it compositely aggregates them). In the DCD the same fact appears as a filled diamond at the Board end, the whole. Each create message points at the new object's box, drawn where it is created.

The standard examples

Each standard example is justified by one of the four criteria. In an exam answer, always name the criterion, not just the principle.

Object createdCreatorCriterion
Monopoly SquareBoardBoard compositely aggregates Squares
POS SalesLineItemSale (via makeLineItem(desc, qty))Sale contains (aggregates) line items
POS SaleRegisterRegister records Sales (a business register has always recorded transactions)
Monopoly PlayerMonopolyGameHas the initialising data (player names from user input)
Payment initialised with the sale totalSaleHas the initialising data (it knows the total)
Library BorrowedItemBorrowingRecordContains/compositely aggregates BorrowedItems
Tony's Pizza Pizza, OrderLineItemOrderThe order ultimately contains them

In Tony's Pizza the Order itself had no good domain creator (making the Customer create it felt wrong), so the controller's startOrder() creates it and records it as currentOrder.

Contraindications and benefits

Contraindication · complex creation

If creation is complex, hand it to a helper Concrete Factory or Abstract Factory (Part VI) instead of the class Creator suggests. "Complex" means things like recycling instances for performance, or conditionally creating one of a family of similar classes based on some external property or context.

Benefits: Creator supports Low Coupling, which means fewer maintenance dependencies and more reuse. Related: Low Coupling, Factory, Whole-Part.

Check yourselfA Payment must be initialised with the sale total. Which class should create it, and by which Creator criterion?

Sale, because it has the initialising data: it knows its total. (Sale also closely uses its Payment, and choosing Sale keeps coupling low, as 4.4 shows.)

Check yourselfIn the library system, a BorrowingRecord contains one or more BorrowedItems, and the BorrowingKiosk records BorrowingRecords. Who creates a BorrowedItem?

BorrowingRecord, by Creator, because it contains (compositely aggregates) BorrowedItems. The kiosk records records, not the items inside them, so it is not the natural creator of BorrowedItems.

Check yourselfA system must create one of several kinds of tax-calculator adapter depending on a setting in a configuration file. Is Creator the right answer for "who creates the adapter"?

No. This is conditionally creating one of a family of similar classes based on an external property, which is Creator's contraindication. Use a Factory (a Pure Fabrication) instead.

In short

B creates A if B contains, records, closely uses, or has the initialising data for A; prefer containment. It adds no new coupling, because B is already connected to A. For complex or conditional creation, use a Factory instead.

4.3

Information Expert exam

A real design has hundreds of classes and thousands of responsibilities. You need a default rule for placing them that tends to produce designs that are easy to understand, maintain, extend and reuse. Information Expert ("Expert") is that rule.

Problem

What is a general principle for assigning responsibilities to objects?

Solution

Give the responsibility to the information expert: the class that has the information needed to fulfil it. This works for both doing and knowing responsibilities.

Where to look: if suitable classes already exist in the Design Model, look there first. Otherwise look in the Domain Model and create a matching design class (LRG).

The procedure exam

Expert is the principle to consider first, unless the problem is a creation problem (use Creator) or a system-event problem (use Controller). Applying it takes four steps. Step through them for Larman's classic question, "who knows the sale total?"

Applying Expert to "who knows the sale total?"
Sale -time: DateTime +getTotal(): Money lineItems1..* SalesLineItem -quantity: Integer +getSubtotal(): Money description1 ProductDescription -price: Money +getPrice(): Money :Sale tot = getTotal() by Expert li : SalesLineItem loop [for each li in lineItems] st = getSubtotal() by Expert :ProductDescription pr = getPrice() by Expert pr st = quantity * pr tot = sum of st 1 State the responsibility Who should be responsible for knowing the sale total? 2 Summarise the information total = sum of line-item subtotals subtotal = quantity × price 3 Tabulate who has each piece Sale: all its SalesLineItems SalesLineItem: its quantity ProductDescription: the price
  1. Step 1: state the responsibility clearly. "Who should be responsible for knowing the sale total?" The candidate software classes come from the domain model: Sale, SalesLineItem, ProductDescription. None has any methods yet.
  2. Step 2: summarise the information needed. The total is the sum of the line-item subtotals, and each subtotal is quantity × price.
  3. Step 3: tabulate who has each piece. Sale knows all its line items (through the lineItems association); SalesLineItem has the quantity; ProductDescription has the price. The information is spread over three classes, so there will be three partial experts.
  4. Step 4a: Sale knows the total. Sale is the expert on the whole (it has all the line items), so getTotal() goes to Sale, by Expert. The DCD gains +getTotal(): Money.
  5. Step 4b: each line item knows its subtotal. Sale cannot compute a subtotal itself: the quantity lives in SalesLineItem. So Sale loops over its line items and asks each one, getSubtotal(), by Expert.
  6. Step 4c: the description knows the price. The line item has the quantity but not the price, so it asks its ProductDescription, getPrice(), by Expert.
  7. The partial experts collaborate. Each class does the part it has the data for, and the answers flow back: price → subtotal (quantity × price) → total (sum of subtotals). No class had to reach into another's data.

The code follows the diagram line for line: each method is on the class that owns the data it uses.

public class Sale {
    private List<SalesLineItem> lineItems = new ArrayList<>();
    public Money getTotal() {                       // Sale knows all its line items
        Money total = new Money(0);
        for (SalesLineItem sli : lineItems) total = total.add(sli.getSubtotal());
        return total;
    }
}
public class SalesLineItem {
    private int quantity;
    private ProductDescription description;         // association to its description
    public Money getSubtotal() { return description.getPrice().times(quantity); }
}

Key ideas

Partial experts collaborate. When the information is spread across several objects, each does its part and they pass messages to share the work. The sale total needed three.

Intuition · "Do It Myself"

Expert embodies Coad's "Do It Myself" or animation principle: a software object does the things that would normally be done to the inanimate real-world thing it represents. A paper receipt doesn't add itself up, but a software Sale does. In a company, the analogy is giving a task to the person who has the information, as when the CFO prepares the profit-and-loss statement.

Expert supports Low Coupling. Put the responsibility anywhere other than with the information, and the information has to be shipped away from its home, which adds dependencies. The pair below makes that visible.

Register Sale SalesLineItem ProductDescription getLineItems() getQuantity() getPrice() Register now depends on all three classes
Without Expert (illustration). If Register computed the total, it would have to pull every quantity and price out of other objects, coupling itself to classes it otherwise never needs.
Register Sale SalesLineItem ProductDescription getTotal() getSubtotal() getPrice() each class talks only to the class it already knows
With Expert. The total is computed where the line items are, and each subtotal where the quantity is. Register needs only Sale, which it knows anyway (it is the current sale).

More course examples

Every Expert answer has the same shape: "X does it, because X has Y". The table collects the ones from the course.

SystemResponsibilityExpertBecause it has…
MonopolygetSquare(name)Boardall the Squares (it aggregates them)
POSgetProductDescription(itemID)ProductCatalogall the descriptions (it contains them)
POSbecomeComplete()Salethe isComplete attribute
LibraryhasReachedLimit()MemberborrowLimit, and its association to its BorrowingRecords
Tony's PizzaaddTopping, removeTopping, editSizePizzaits own toppings and size

When there are several partial experts, place the responsibility with the dominant expert, the one with most of the information. If no expert dominates, compare coupling and cohesion. If that is still a tie, consider likely future evolution (Monopoly's takeTurn, 4.10, is the worked case).

Contraindications exam

Contraindication · who saves a Sale to the database?

Expert says Sale, since it has the data. But that design has four problems:

  • Sale now contains SQL/JDBC code that has nothing to do with "being a sale": it is incohesive;
  • it is coupled to a technical service (JDBC) rather than to other domain objects: it is highly coupled;
  • every persistent class would repeat similar code: duplication and poor reuse;
  • domain logic and database logic are mixed, which violates separation of concerns and widens the representational gap.

The fix is a separate, invented class, PersistentStorage: a Pure Fabrication, drawn in 4.7.

Benefits: Expert preserves encapsulation, because objects use their own information, and that usually gives Low Coupling. It also spreads behaviour over lightweight classes, which usually gives High Cohesion. Also known as: "Place responsibilities with data", "That which knows, does", "Do It Myself", "Put services with the attributes they work on".

Check yourselfThe balance of a sale is the payment amount minus the total. Sale and Payment both hold part of that information. Who should compute it, and why?

Sale.getBalance(). Both are partial experts, so compare coupling: Sale already has visibility to its Payment (it created it), whereas putting the method in Payment would give Payment new visibility to Sale. "By Expert and Low Coupling."

Check yourselfYou must design "who checks whether a library member has reached their borrowing limit?". Apply the Expert procedure.

(1) State it: who knows whether a member has reached the limit? (2) Information needed: the member's borrowLimit and how many items they currently have borrowed. (3) Who has it: Member has borrowLimit and is associated with its BorrowingRecords. (4) Assign hasReachedLimit() to Member, by Expert. 4.11 shows why the alternatives (kiosk, record) cost more coupling.

Check yourselfSpot the flaw: "By Information Expert, Sale should contain the JDBC code that saves it, because it has all the data."

This is Expert's textbook contraindication. Saving makes Sale incohesive (database work is not sale-ness), couples it to a technical service (JDBC), duplicates the same code in every persistent class, and mixes domain and DB concerns. Give the job to a Pure Fabrication such as PersistentStorage.

In short

Give a responsibility to the class that has the information. State the responsibility, list the information, tabulate who has it, assign each part to its expert; partial experts collaborate. Expert is the default rule (try it first unless it is a creation or system-event problem), but it backfires for technical services like persistence.

4.4

Low Coupling and High Cohesion exam

Expert, Creator and Controller tell you where to try putting a responsibility. Low Coupling and High Cohesion are how you judge the result, and how you choose when two answers seem equally valid. They are a pair: Larman calls them "yin and yang", because a design that is bad on one is usually bad on the other.

Coupling

Definition · Coupling

Coupling is how strongly one element is connected to, has knowledge of, or relies on other elements. If A depends on B, a change to B may force a change to A.

A class with high coupling suffers in three ways: it is forced to change when the classes it depends on change; it is hard to understand in isolation; and it is hard to reuse, because everything it depends on has to come along with it.

Problem

How to support low dependency, low change impact and increased reuse? (Short form in ch. 17: "How to reduce the impact of change?")

Solution

Assign responsibilities so that (unnecessary) coupling stays low. Use this principle to evaluate alternatives.

Five common forms of coupling from TypeX to TypeY exam

"Coupling" sounds vague until you can point to it in a diagram or in code. These are the five forms to recognise, each with a course example.

TypeX TypeY Register Sale currentSale1 1. X has an attribute of type Y private Sale currentSale; Register Sale getTotal() 2. X calls services of a Y object sale.getTotal(); Sale Payment 3. Y is a parameter, local or return type void addPayment(Payment p) GoSquare Square 4. X is a subclass of Y (the strongest form) class GoSquare extends Square TaxMasterAdapter «interface»ITaxCalculatorAdapter 5. Y is an interface and X implements it implements ITaxCalculatorAdapter
Every arrow is a dependency. Each form means "if Y changes, X may have to change". Notice that the line style already tells you the form: solid with an open arrow (attribute), a message (call), dashed (use as a type), triangle (inheritance). Subclassing couples X to everything Y is and does, which is why it is the strongest.

Worked comparisons

Low Coupling is used to choose between designs. Three comparisons from the course show how. First, Board versus an arbitrary Dog for getSquare in Monopoly.

Dog Board Square getSquares() searches them two classes now depend on Square
Dog does it. Dog fetches the whole collection from Board and searches it. A change to Square's interface now hits Dog and Board, and the extra step is less efficient too.
caller Board Square getSquare(name) only Board depends on Square
Board does it. The expert keeps the search to itself, so overall coupling is lower. This is exactly why Expert usually works: it supports Low Coupling.

Second, who computes a line's subtotal? ProductDescription knows the price, so Expert alone might pick it. But then Sale, when summing, would have to talk to ProductDescription as well: unnecessary coupling. Low Coupling therefore prefers SalesLineItem, which knows its quantity and its description.

Third, the comparison most often examined: who creates the Payment? Step between the two tabs and count the arrows in the dependency graphs.

Sequence Resulting dependencies :Register :Sale makePayment(cash) create(cash) p : Payment addPayment(p) Register Sale Payment new 3 dependencies, including Register → Payment
Creator's first suggestion. A real register records payments, so Creator points at Register. But Register then has to know Payment (a new, red dependency), and Sale still has to know Payment to store it. Register also takes on one more piece of work.
Sequence Resulting dependencies :Register :Sale makePayment(cash) makePayment(cash) create(cash) by Creator and Low Coupling :Payment Register Sale Payment 2 dependencies: Register never sees Payment
The better design. Register just forwards makePayment; Sale creates the Payment. Nothing new is coupled, because Sale must know Payment anyway. So Low Coupling and Creator suggest different answers, and Low Coupling wins. High Cohesion prefers this design too, because Register does less.
Slides versus textbook

The slides say "By Expert, Register should be responsible for creating Payment". The textbook attributes the Register suggestion to Creator (Register records Payments). Use Creator in your answers; the final answer, Sale, is the same either way.

Discussion and contraindications

Low Coupling is an evaluative principle that you apply to every design decision, and it cannot be considered in isolation from Expert and High Cohesion. Subclassing is strong coupling, so choose it carefully: a PersistentObject superclass that every domain class extends gives them persistence for free, but couples domain objects to a technical service and mixes architectural concerns.

There is no absolute measure of when coupling is "too high"; instead, ask whether increasing it will cause problems. Generic classes that are likely to be reused should have especially low coupling. And less is not always better:

Too high Moderate: normal and necessary "No coupling at all" one bloated object does everything itself passive data holders
Both extremes are bad. Coupling taken to the extreme (none at all) goes against the OO metaphor of connected objects sending messages, and gives a few bloated, incohesive "active" objects next to many passive data holders. Aim for the middle: moderate coupling, mostly to stable things.
Contraindication · pick your battles

High coupling to stable, pervasive elements is rarely a problem; coupling to java.util, for instance, is fine. The problem is coupling to elements that are unstable in their interface, their implementation or their mere presence. Effort spent lowering coupling with no realistic motivation is wasted, whereas NextGen's tax-calculator interfaces really do vary, so lowering coupling there pays off.

Benefits: elements are unaffected by changes in other components, simple to understand in isolation, and convenient to reuse. Related: Protected Variations. Coupling and cohesion as design principles were identified by Larry Constantine.

Cohesion

Definition · Cohesion

Cohesion (strictly, functional cohesion) is how strongly related and focused the responsibilities of an element are. An element with highly related responsibilities that does not do a huge amount of work has high cohesion, so both the amount of code and how related it is matter. Booch: elements that "all work together to provide some well-bounded behavior".

A low-cohesion class does many unrelated things, or simply too much. It is hard to understand, reuse and maintain, and it is delicate: constantly affected by change. Such classes are often very coarse-grained, or have taken on work they should have delegated.

Problem

How to keep objects focused, understandable and manageable, and as a side effect support Low Coupling?

Solution

Assign responsibilities so that cohesion stays high. Use it to evaluate alternatives.

Levels of cohesion exam

Larman describes four levels, from very low to high. Notice that the remedy at the two lowest levels is to split the class.

Very low RDB-RPC-Interface database access remote calls Solely responsible for many things in very different functional areas. Split into two families of classes. Low RDBInterface hundreds or thousands of methods Solely responsible for a complex task in one functional area. Split into a family of lightweight classes. Moderate Company knows employees knows finances Lightweight, sole responsibilities in a few areas related to the concept but not to each other. Acceptable: few methods, little code. High RDBInterface other RDB classes … about a dozen Moderate responsibilities in one functional area; collaborates with other classes to do the work. The goal.
Unrelated areas, too much work, or neither. The first row fails because the areas are unrelated; the second because one class does an enormous amount of related work alone. The rule of thumb: a highly cohesive class has a relatively small number of methods with highly related functionality and, when the task is large, collaborates.

Examples

Monopoly's playGame shows the difference between doing the work and delegating it.

MonopolyGame +playGame()-doA()-doB() -doC()… 100 methods 100 methods × 200 lines = 20K lines one class does all the work itself
Low cohesion. The game object does everything itself (the slides' example). It is bloated, hard to understand and delicate.
MonopolyGame +playGame()-playRound() Player takeTurn() Cup Board roll() getSquare() small, focused classes share the work
High cohesion. The game delegates each turn to the players, who use the cup and the board. Even at the method level, the private helper playRound is a small, single-purpose method named in domain vocabulary.

In POS, having Register create Payment is harmless on its own. The point is the trend: if Register does part of the work for each of the ~50 system operations it receives, it becomes a bloated, incohesive object. Delegating Payment creation to Sale gives higher cohesion and lower coupling. (The library version of this argument, hasReachedLimit in the kiosk, is in 4.11.)

Intuition · yin and yang

Bad cohesion usually brings bad coupling, and vice versa. A GUI widget that paints itself, saves to a database and calls remote services is incohesive and coupled to many unrelated elements. Modular design means decomposing a system into cohesive, loosely coupled modules (Booch), and you get there with single-purpose methods and classes that group related concerns.

Contraindications · when lower cohesion is justified
  • Grouping for a specialist. Put all the embedded SQL in one class, RDBOperations, so the one SQL expert can maintain it in one place.
  • Distributed or remote server objects. Remote calls are expensive, so use fewer, larger, less cohesive server objects. This is the Coarse-Grained Remote Interface pattern: one setData(...) call instead of setName, setSalary and setHireDate.

The slides generalise this: low cohesion may be needed to meet strict non-functional requirements such as performance.

Benefits: clearer, easier-to-understand design; simpler maintenance and enhancement; Low Coupling is often supported; fine-grained, focused classes are easier to reuse.

Check yourselfName the form of coupling in each: (a) class CashPayment extends Payment; (b) Money getTotal() in Register, which returns currentSale.getTotal(); (c) private ProductCatalog catalog; in Register.

(a) subclass, the strongest form: CashPayment is coupled to Payment. (b) two forms at once: Register calls a service of Sale, and uses Money as a return type. (c) an attribute referring to a ProductCatalog.

Check yourselfTrue or false: "The ideal design has no coupling at all, so every class can be reused on its own."

False. Coupling taken to the extreme goes against the OO metaphor of collaborating objects and produces a few bloated, incohesive active objects plus passive data holders. Moderate coupling is normal and necessary. Coupling to stable elements (like java.util) is rarely a problem; worry about coupling to unstable ones.

Check yourselfA ReportManager class formats reports, sends emails, validates user passwords and caches database rows. Which cohesion level is this, what is the remedy, and which MCQ label fits?

Very low cohesion: one class is solely responsible for many things in very different functional areas. Split it into separate families of classes. If a question asks what is wrong with it, the label is Low Cohesion (the problem); the principle that fixes it is High Cohesion.

Check yourselfA team merges setName, setSalary and setHireDate on a remote employee server into one setData(...). Has it broken High Cohesion, and is that acceptable?

It has lowered cohesion slightly, deliberately. It is a recognised contraindication: remote calls are expensive, so a Coarse-Grained Remote Interface with fewer, larger operations is justified by a performance requirement.

In short
  • Coupling = dependence on other elements; five forms (attribute, call, type use, subclass, implements). Keep unnecessary coupling low, especially to unstable things.
  • Cohesion = how focused an element's responsibilities are; split classes that cover unrelated areas or do too much.
  • Both are evaluative: use them to choose between alternatives (Payment is created by Sale, not Register). Both have contraindications (stable libraries; performance).
4.5

Controller exam

When a cashier presses "End Sale", a window receives the click. Something in the domain must then actually end the sale. If the window did that work itself, the business logic would be stuck inside one UI technology. Controller decides which domain-side object receives each request from the UI.

Definition · System event and controller

A system event (or system operation) is a major input event to the system, typically from a GUI operated by an actor (a cashier pressing "End Sale"); external messages and sensor signals also count. These are the operations on the SSD. A controller is the first object beyond the UI layer that receives and handles a system operation message.

Problem

What first object beyond the UI layer receives and coordinates ("controls") a system operation?

Solution

Give the responsibility to a class representing one of:

  1. the overall "system", a "root object", a device the software runs in, or a major subsystem: all variants of a façade controller;
  2. a use case scenario in which the system event occurs: a use case (or session) controller.

Façade controller examples: Register (the POS terminal device), POSSystem, Store (root), MonopolyGame (root), Phone, BankCashMachine, ChessGame. Use case controllers are conventionally named <UseCaseName>Handler, …Coordinator or …Session: ProcessSaleHandler, PlayMonopolyGameHandler, OrderHandler. Use the same controller class for all system events in the same use case scenario, so it can keep that use case's state. (A session is one conversation with an actor, often organised as a use case session.)

Corollary: "window", "view" and "document" classes are not on the list. They receive UI events and delegate to a controller; they must not fulfil system operations themselves. Compare the two designs for enterItem.

UI layer Domain layer Cashier :SaleJFrame :Register :Sale presses button actionPerformed(actionEvent) converts the input: no business logic enterItem(itemID, qty) by Controller makeLineItem(desc, qty) the controller delegates the work
The window only converts and forwards. The UI layer turns a button press into a call; the first message to cross into the domain layer is the system operation enterItem, received by the controller, which hands the real work to Sale.
UI layer Domain layer Cashier :SaleJFrame :Register bypassed :Sale presses button makeLineItem(desc, qty) business logic in the UI: tied to one UI technology and cannot be reused
The undesirable alternative. The window talks to Sale directly, so application logic lives in the presentation layer. Swap Swing for a web page, or run the system in batch mode, and this logic has to be rewritten.

In code, the window converts input and delegates; the controller coordinates without doing the work itself.

// UI layer: the window only converts input and delegates
public class ProcessSaleJFrame extends JFrame {
    private Register register;                      // reference to the domain-layer controller
    public ProcessSaleJFrame(Register register) { this.register = register; }
    private void onEnterItemClicked() {             // button click handler
        ItemID id = Transformer.toItemID(txtId.getText());
        int qty = Transformer.toInt(txtQty.getText());
        register.enterItem(id, qty);                // crosses from UI layer to domain layer
    }
}
// Domain layer: the controller coordinates, it does not do the work
public class Register {
    private ProductCatalog catalog;
    private Sale currentSale;
    public void makeNewSale()                     { currentSale = new Sale(); }                  // Creator
    public void enterItem(ItemID id, int qty)     { currentSale.makeLineItem(catalog.getProductDescription(id), qty); }
    public void endSale()                         { currentSale.becomeComplete(); }
    public void makePayment(Money cash)           { currentSale.makePayment(cash); }
}

Controller is a delegation pattern: it acts as a kind of façade onto the domain layer from the UI layer, and it should coordinate and do little itself. Tony's Pizza calls it a "postbox": its methods correspond to system operations and just call the right domain object.

Façade controller versus use-case controller exam

Façade controller Use-case (session) controllers UI Register +makeNewSale()+enterItem(id, qty) +endSale()+makePayment(cash) one object represents the whole system, a root object, a device or a subsystem UI ProcessSaleHandler HandleReturnsHandler not domain objects: Pure Fabrications one controller per use case scenario, which keeps that use case's state
Same job, different scope. A façade controller is usually a domain concept (LRG); a use-case controller is an invented class, which is why it counts as a Pure Fabrication. Both are controllers; neither belongs to the UI.
Façade controllerUse-case (session) controller
RepresentsWhole system, root object, device or subsystemOne use case scenario
NamesRegister, POSSystem, Store, MonopolyGameProcessSaleHandler, HandleReturnsHandler, OrderHandler
Choose whenThere are not too many system events, or the UI cannot route messages to different controllers (e.g. a message-processing system)The façade would become bloated (low cohesion, high coupling); many system events across different processes
ExtraOften a domain concept (LRG)Not a domain object: a Pure Fabrication; a natural place to track use-case state

Larman chose Register for NextGen and MonopolyGame for Monopoly because each has only a few system operations (Monopoly has just two, initialize and playGame). In Tony's Pizza the presenter chose a use-case controller, OrderHandler, because one controller for the whole system (ordering, deliveries, ingredients) would get bloated.

GUI OrderHandler +startOrder(): Order +addPizzaToOrder(style, size) +addPizzaTopping(pizza, topping) +removePizzaTopping(pizza, topping) +getTotal(): double Order currentOrder0..1 the single point where the GUI is coupled to the domain
A use-case controller in the wild. OrderHandler keeps the state of the ordering use case (the order in progress, 0..1) and offers one method per system operation. It reduces the coupling from the GUI to the domain to a single point.

Benefits, bloat and the cure

Benefits. (1) Reuse and pluggable interfaces: application logic is not bound to a window, so it can be reused, the UI can be replaced, or the system can run in batch mode. (2) You can reason about the state of the use case: for example, enforcing that makePayment cannot happen before endSale is easiest when one controller handles the whole use case.

Bloated controller exam

Three signs that a controller has become bloated:

  • a single controller receives all system events, and there are many of them (common with façade controllers);
  • the controller performs the work itself instead of delegating, which usually violates Expert and High Cohesion;
  • it has many attributes and keeps significant system or domain information that belongs to other objects, or duplicates information found elsewhere.

Two cures: (1) add more controllers, using use-case controllers instead of one façade; (2) design the controller so it mainly delegates.

UI AirlineSystem -reservations-schedules-fares -customers… many more +makeReservation()+changeSchedule()+setFare() +cancelReservation()… every system event all events receives everything, does the work, holds others' data
Bloated (illustration). One façade receives every event, does the work itself and hoards domain data: all three signs at once.
UI MakeReservationHandler ManageSchedulesHandler ManageFaresHandler Reservation Schedule Fare several small controllers that delegate
Cured. Larman's airline example of more controllers: MakeReservationHandler, ManageSchedulesHandler, ManageFaresHandler, each passing the work on (green arrows) to the objects that own the data.

Things not to confuse

  • UI layer does not handle system events exam. That is why a JFrame, a web page or a main method must forward the event to a domain controller.
  • GRASP controller ≠ Web-MVC controller. The MVC controller (for example a Struts Action) belongs to the UI layer and controls page flow. The GRASP controller belongs to the domain/application layer and does not know which UI technology is in use.
  • UP terms: boundary objects are interface abstractions, entity objects are application-independent (often persistent) domain objects, and control objects are use-case handlers as in this pattern.
  • In message-handling systems such as a telecom switch, each message is typically represented and handled by a Command object (GoF).

Related: Command; Façade (a façade controller is a kind of Façade); Layers; Pure Fabrication (a use-case controller is one). The lectures covered Controller only in workshop supplementary material (Workshop 4, Exercise 4; Tony's Pizza week 4), so the textbook (ch. 17.13) is the authority.

Check yourselfA student's design has CheckoutPage (a web page) call cart.calculateDiscount() and order.create() directly. Which principle is broken and how do you fix it?

Controller (and its corollary): a UI object is fulfilling a system operation. Add a domain-layer controller (for example a CheckoutHandler use-case controller, or a façade such as Store) that receives the system operation, say checkout(...), from the page and delegates to the domain objects. The page only converts input and forwards it.

Check yourselfA vending-machine program has three system operations. Another system, a hospital, has over sixty, across admissions, billing and pharmacy. Which kind of controller suits each?

Vending machine: a façade controller representing the device (like Register), because there are few system events. Hospital: use-case controllers (e.g. AdmitPatientHandler, BillingHandler), because one façade would become bloated, with low cohesion and high coupling.

Check yourselfAn MCQ describes "one handler class that receives every request and does most of the processing itself". Which GRASP answers fit?

It describes a bloated controller, so Controller is the principle at stake (cure: use-case controllers plus delegation). If the options phrase it as the problem, the answer is Low Cohesion.

Check yourselfIs a Struts Action (a Web-MVC controller) a GRASP controller?

No. It belongs to the UI layer and controls page flow. A GRASP controller sits in the domain/application layer and is independent of the UI technology; the Struts Action would forward the system operation to it.

In short

The first object beyond the UI that receives a system operation is a controller: a façade (system, root, device, subsystem) when there are few events, a use-case controller (a Pure Fabrication) when a façade would bloat. UI objects never handle system events, and controllers coordinate and delegate rather than do the work.

4.6

Polymorphism exam

Whenever behaviour depends on what kind of thing you have, the tempting design is an if or switch on its type. That works until a new kind arrives, and then every such conditional, often scattered across many classes, has to be found and edited. Polymorphism removes the conditionals.

Problem

(1) How to handle alternatives based on type? (2) How to create pluggable software components, so that one server component can replace another without affecting the client?

Solution

When related alternatives or behaviours vary by type (class), give the responsibility for the behaviour to the types for which it varies, using polymorphic operations: operations with the same interface (name and signature) in different classes.

Corollary: do not test for the type of an object and use conditional logic to choose behaviour. Also known as "Choosing Message" and "Don't Ask 'What Kind?'".

Monopoly squares

Landing on Go gives you $200, Income Tax charges you tax, a Regular square does nothing, and Go To Jail moves you to jail. The types that vary are the kinds of square, and the varying operation is "what happens when a player lands", so it is named landedOn. Square types are domain concepts too, so the domain model gets a generalisation hierarchy as well.

// bad design (the corollary forbids this)
SWITCH ON square.type
  CASE GoSquare:        player receives $200
  CASE IncomeTaxSquare: player pays tax
  ...

Every new kind of square means editing this switch, and any other place that switches on square type.

Player -cash: int +takeTurn()+addCash(amt: int)+reduceCash(amt: int) +getNetWorth(): int+setLocation(s: Square) Square -name: String +landedOn(p: Player) {abstract} location1 RegularSquare+landedOn(p: Player) GoSquare+landedOn(p: Player) IncomeTaxSquare+landedOn(p: Player) GoToJailSquare+landedOn(p: Player) jail1
One operation, four behaviours. Square and its landedOn are written in italics because they are abstract (you may write {abstract} instead). Each subclass overrides landedOn, so the caller just sends the message and the right version runs.
public abstract class Square {
    public abstract void landedOn(Player p);       // {abstract}: no sensible default
}
public class GoSquare extends Square {
    public void landedOn(Player p) { p.addCash(200); }                        // Player is Expert on its cash
}
public class RegularSquare extends Square {
    public void landedOn(Player p) { }                                        // NO-OP avoids special-case logic
}
public class IncomeTaxSquare extends Square {
    public void landedOn(Player p) { p.reduceCash(Math.min(200, p.getNetWorth() / 10)); }
}
public class GoToJailSquare extends Square {
    private Square jail;                                                      // set at initialisation
    public void landedOn(Player p) { p.setLocation(jail); }
}

Design decisions in the dynamic model

Who sends landedOn? The Player, at the end of takeTurn: by Expert and Low Coupling, it already knows its location square. The player passes itself as a parameter, landedOn(p), which gives the square parameter visibility to the player, so it can send addCash, getNetWorth, reduceCash or setLocation, each assigned to Player by Expert.

Drawing polymorphic cases. You can draw a separate sequence diagram per subclass, or use sd/ref frames. The lecture and Tony's Pizza use an alt frame guarded by the runtime type, as below. That guard only documents which implementation runs; the code contains no type test.

p : Player loc : Square landedOn(p) by Polymorphism alt [loc is a GoSquare] addCash(200) [loc is a RegularSquare] do nothing (an empty method) [loc is an IncomeTaxSquare] w = getNetWorth() reduceCash(min(200, w / 10)) [loc is a GoToJailSquare] setLocation(jail)
The alt frame documents, the code dispatches. One message, landedOn(p); four implementations. The square calls back to the player it was given as a parameter. Note the RegularSquare branch: an empty method is still a real method.

RegularSquare.landedOn is an empty (NO-OP) method. It exists so that the client never has to special-case anything. The general guideline: declare the polymorphic operation {abstract} in the superclass unless there is a sensible default behaviour.

Refactoring for coupling. In iteration 1 the Piece knew the location, and Player kept asking it. When object A keeps needing B's data, either A should hold that data or B should have the responsibility (Expert). So in iteration 2 Player holds location directly, and Piece disappears from the design.

Other course examples

NextGen tax calculators. The third-party calculators (Tax-Master, Good-As-Gold TaxPro, …) have different interfaces: raw TCP socket, SOAP, Java RMI. Adapting differs by calculator type, so each adapter implements a polymorphic getTaxes(Sale): List<TaxLineItem> from the interface ITaxCalculatorAdapter. Each adapter is a local software object that calls its external calculator through that calculator's native API. (The full design is stepped through in 4.8.)

Tony's Pizza. Pizza and Drink both have getPrice(): double but compute it differently.

OrderLineItem Pizza Drink 0..10..1 awkward: "0..1 pizza and 0..1 drink", and the price logic must ask which one is set
Without Polymorphism. Each line item may hold a pizza or a drink, so every caller must check which is present.
OrderLineItem Item+getPrice(): double 1 Pizza+getPrice(): double Drink+getPrice(): double new items (garlic bread, wings) = one new subclass
With Polymorphism. An abstract Item with abstract getPrice(); OrderLineItem holds exactly one Item. New item types can be added without changing OrderLineItem or Order.

Library. When videos as well as books can be borrowed, an Item interface (getTitle, getDetail, getQuantity) is implemented by Book and Video, and getDetail is polymorphic.

When to design with interfaces

Use an interface when you want polymorphism without committing to a class hierarchy. With only an abstract superclass, every new implementation must subclass it, which is limiting in single-inheritance Java. A rule of thumb: for an abstract superclass C1, consider an interface I1 holding C1's public signatures and have C1 implement I1. That leaves an evolution point for future cases.

Contraindication

Avoid speculative "future-proofing" with interfaces and polymorphism at points where variation is improbable. Be realistic about how likely the variation is before paying for flexibility.

Benefits: new variations are easy to add, and new implementations can be introduced without affecting clients. Related: Protected Variations; many GoF patterns rely on polymorphism, including Adapter, Command, Composite, Proxy, State and Strategy (and Decorator).

Check yourselfA Shape class has draw() containing if (type == CIRCLE) … else if (type == SQUARE) …. What does Polymorphism say, and what changes when a triangle is added?

Don't test for type: make draw() a polymorphic (abstract) operation of Shape and give each subclass (Circle, Square) its own version. Adding a triangle is then one new subclass, Triangle, with no edits to existing conditionals or to the code that calls draw().

Check yourselfAn MCQ describes a person whose behaviour changes depending on the role they are playing (for example student or tutor). Which GRASP answer was given as official?

Polymorphism: this is the official answer to 2021 Semester 2 Q1.1. Behaviour that varies by the role (type) an object plays goes into polymorphic operations. Prefer the GoF answers only when the stem is more specific: Strategy for interchangeable algorithms for one context object, State when behaviour changes with the object's state.

Check yourselfWhy does RegularSquare need an empty landedOn method at all? Couldn't the player just skip calling it?

Skipping the call would mean the player tests whether the square is a regular one: exactly the type test the corollary forbids. The NO-OP method lets every square be treated the same way, so the client never special-cases anything.

In short

When behaviour varies by type, give each type its own version of one polymorphic operation and never switch on type. An alt frame may document the cases; the code doesn't test. Use interfaces for pluggability, but only where variation is realistic.

4.7

Pure Fabrication and Indirection

Expert works when the information and the behaviour naturally belong together. Sometimes they don't: saving to a database, rolling dice for any game, or talking to an outside system. Forcing those jobs onto domain classes ruins their cohesion and coupling. These two principles give such jobs a home.

Pure Fabrication exam

Problem

Which object should have the responsibility when you don't want to violate High Cohesion and Low Coupling, but the solutions offered by Expert (and other patterns) are not appropriate?

Solution

Give a highly cohesive set of responsibilities to an artificial or convenience class that does not represent a problem-domain concept, made up purely to support high cohesion, low coupling and reuse.

Ideally the fabrication's design is very clean, or "pure"; the name also plays on the English idiom "pure fabrication", meaning something made up. On this page, invented classes are shaded green.

Example 1: saving a Sale exam

Sale+save() // SQL Payment+save() // SQL ProductDescr.+save() // SQL «technical service»JDBC incohesive · coupled to JDBC · same code repeated
Expert alone. Sale has the data, so Expert says Sale saves itself. Every persistent class then repeats the SQL and depends on a technical service.
Sale Payment ProductDescr. domain classes: no SQL, no JDBC PersistentStorage +insert(o: Object)+update(o: Object) «technical service»JDBC one cohesive, reusable class
Pure Fabrication. A store manager would not recognise "persistent storage objects": the class exists for developers' convenience. Sale stays cohesive and loosely coupled; PersistentStorage is itself cohesive (one purpose) and generic, so it is reusable.

A real persistence framework uses many classes behind such a front-end façade (Part VI).

Example 2: rolling the dice (Cup)

In iteration 1, Player rolled and summed the dice. That had two problems: dice are general objects useful in many games, but the summing service was tied to Monopoly's Player; and you could not ask for the current total without rolling again. Every other domain-inspired class has the same problems (the slides note that by the domain model and Expert, MonopolyGame would be the candidate, which is acceptable but gives low cohesion). So the design fabricates a Cup that holds the dice, rolls them and knows their total. Larman still picks domain-flavoured vocabulary, since real games use dice cups.

Static: the fabricated Cup Dynamic: a turn in iteration 2 Player+takeTurn() Cup-total: int +roll()+getTotal(): int cup1 Die-faceValue: int +roll()+getFaceValue(): int dice2..* p : Player :Cup :Board loc : Square roll() by Pure Fabrication fvTot = getTotal() loc = getSquare(loc, fvTot) by Expert landedOn(p) by Polymorphism
Three principles in one turn. The Cup is fabricated; Board finds the new square because it knows all the squares (Expert); the square reacts by its own type (Polymorphism). Larman labels key messages with their principle, as here.
public class Cup {                                   // not in the Monopoly domain model
    private List<Die> dice = new ArrayList<>();
    private int total;
    public void roll() {                             // command: changes state, returns nothing
        total = 0;
        for (Die d : dice) { d.roll(); total += d.getFaceValue(); }
    }
    public int getTotal() { return total; }          // query: can be asked without re-rolling
}

Example 3: the library's BorrowingHandler

In the library system, BorrowingKiosk is the controller that receives UI input. That leaves the question of who runs the application logic (newBorrowing, returnItem, getItemAvailability). With High Cohesion and Low Coupling in mind, none of the existing domain classes fits, so the design fabricates one.

BorrowingKiosk +memberLogin()+listItem() +returnItem()+newBorrowing() controller: UI-facing BorrowingHandler +assignCurMember(id)+listItem() +getAvailability(item)+returnItem()+newBorrowing(items) Pure Fabrication: application logic delegates Member BorrowingRecord Book
Controller plus fabrication. The kiosk keeps only its UI-facing operations and delegates the application logic to the invented BorrowingHandler, which in turn works with the domain classes.

You have already met other Pure Fabrications: use-case controllers, Factories (Part VI) and Adapters such as TaxMasterAdapter. In fact Larman says all GoF patterns are Pure Fabrications.

Representational versus behavioural decomposition

Pure Fabrication rests on a distinction between two ways of carving up a design.

Representational decomposition

A class represents a domain thing: Sale, TableOfContents. This supports LRG.

Behavioural decomposition

A class groups related behaviour or an algorithm: TableOfContentsGenerator, PersistentStorage, Cup. Pure Fabrications are function-centric, behavioural objects.

Labelling a class "Pure Fabrication" is not important in itself. The point is that some classes come from the domain and some are invented for the designer's convenience.

Contraindication · overuse

Novices who think in functions tend to overuse Pure Fabrication, so that "functions just become objects". The slides warn that it should not be an excuse to add new objects, and that overuse leads to one class per responsibility.

Overuse also hurts coupling: too many behaviour objects whose responsibilities are separated from the information they need increases coupling. The symptom to watch for: most of an object's data is passed to other objects to reason with. Balance Pure Fabrication with Expert, so representational classes like Sale keep their responsibilities.

Benefits: High Cohesion, because responsibilities sit in a fine-grained, focused class, and more potential for reuse. Related: Low Coupling, High Cohesion. A Pure Fabrication usually takes over a responsibility that Expert would have given to a domain class.

Indirection

Indirection is about decoupling: rather than letting two things depend on each other directly, put something in between them.

Problem

Where to assign a responsibility so that two (or more) things are not directly coupled? How to decouple objects so that low coupling is supported and reuse potential stays high?

Solution

Give the responsibility to an intermediate object that mediates between the other components or services, so they are not directly coupled. The intermediary creates an indirection between them.

Without DependentElement QuestionableElement depends on directly With DependentElement IndirectionElement QuestionableElement hides the questionable element
Add a level in between. If the questionable element (an external system, a database, an unstable API) changes, only the intermediary has to change.

The standard examples

TaxMasterAdapter exam. The external Tax-Master system is reached over TCP sockets. If Sale talked to it directly, Sale would contain all the TCP code: it would depend on one specific protocol and system (high coupling) and mix sale and communication responsibilities (low cohesion). Instead, Sale asks an adapter.

:Sale :TaxMasterAdapter «actor»:TaxMasterSystem taxes = getTaxes(s) by Indirection TCP socket messages tax data taxes
The adapter is a level of indirection to an external system. Sale sees one ordinary method call; all the socket work is inside the adapter. In the diagram the external system is drawn as «actor» :TaxMasterSystem.
  • PersistentStorage mediates between Sale and the database, so it is both a Pure Fabrication and an Indirection.
  • Library. Member sits between BorrowingKiosk and BorrowingRecord: the kiosk asks the member (hasReachedLimit, newBorrowing) rather than reaching the records itself. This intermediary is a domain class, not a fabrication.
  • Controller. A controller is an indirection between the UI layer and the domain layer. A client-side controller also lets services be provided either locally or remotely.

Indirection versus Pure Fabrication

The lecture distinguishes them like this: Indirection means any class acting as an intermediary, whereas Pure Fabrication means an artificial, non-domain class. They overlap a great deal.

Indirection any intermediary Pure Fabrication invented, non-domain Member (library) façade controller (Register) PersistentStorage TaxMasterAdapter use-case controller Cup Factory
Many fabrications exist because of Indirection, and many intermediaries are fabrications. The middle is the common case. Member and Register are intermediaries that are real domain concepts; Cup and a Factory are invented but don't sit between two things.

Discussion. The motivation for Indirection is usually Low Coupling. An old adage says most problems in computer science can be solved by adding another level of indirection; a counter-adage says most performance problems are solved by removing one. Many GoF patterns are specialisations of Indirection: Adapter, Bridge, Façade, Observer and Mediator.

Benefits: lower coupling between components. Related: Protected Variations, Low Coupling, Pure Fabrication.

Check yourselfWhy is Cup a Pure Fabrication even though dice cups exist in real games?

It is not a concept in the Monopoly domain model; it was invented to fix design problems: dice summing tied to Player (poor reuse) and no way to read the total without re-rolling. Larman deliberately gave it a domain-flavoured name, but it exists for cohesion and reuse, which is what makes it a fabrication.

Check yourselfA design has Sale holding only data, plus SaleTotaller, SaleCompleter and SalePaymentMaker, each of which reads Sale's fields to do its job. What is wrong?

Overuse of Pure Fabrication: "functions just become objects", one class per responsibility. The symptom is exactly the warning sign: most of Sale's data is passed to other objects to reason with, which increases coupling and leaves an anaemic Sale. By Expert, those responsibilities belong in Sale itself.

Check yourselfIs every Indirection a Pure Fabrication? Give an example either way.

No. In the library, Member is an intermediary between BorrowingKiosk and BorrowingRecord but is a genuine domain class. TaxMasterAdapter and PersistentStorage, on the other hand, are both: intermediaries and invented classes.

In short
  • Pure Fabrication: when Expert would wreck cohesion or coupling, invent a cohesive non-domain class (PersistentStorage, Cup, BorrowingHandler). Don't overuse it.
  • Indirection: put an intermediary between two things so they aren't directly coupled (TaxMasterAdapter, Member, a controller).
  • They overlap heavily; Indirection is about position, Pure Fabrication about origin.
4.8

Protected Variations exam

Some parts of a system are bound to change: an external API, a business rule, a hardware device. If the rest of the system depends on those parts directly, every change ripples outwards. Protected Variations (PV) is the root principle of GRASP: find the unstable spots and wall them off.

Problem

How to design objects, subsystems and systems so that variations or instability in these elements do not have an undesirable impact on other elements?

Solution

Identify points of predicted variation or instability; assign responsibilities to create a stable "interface" around them. "Interface" is meant broadly, as a means of access, not only a Java interface.

Points of change. A variation point is a variation in the existing system or current requirements, such as the several tax-calculator interfaces that must be supported now. An evolution point is a speculative variation that may arise in future but is not in the current requirements; in the UP these can be documented as Change Cases. PV applies to both.

Example: NextGen tax calculators exam

Applying PV takes two steps: find the instability, then build the stable interface. Here two mechanisms build it, Indirection and Polymorphism.

Protecting Sale from varying tax calculators
Sale Sale holds the TCP code, the other API code, … «actor»Tax-Master «actor»Good-As-Gold TaxPro «actor»a future calculator TaxMasterAdapter+getTaxes(s: Sale) GoodAsGoldTaxProAdapter+getTaxes(s: Sale) TCP socket its own API «interface»ITaxCalculatorAdapter +getTaxes(s: Sale): List<TaxLineItem> NewCalculatorAdapter+getTaxes(s: Sale) its own API point of predicted variation Indirectionprotects against variationof interfaces Polymorphismprotects against variationof behaviours Sale unchanged:it only knows thestable interface
  1. The problem. NextGen must use several third-party tax calculators, each with its own interface (raw TCP socket, SOAP, Java RMI, …), and more may come. If Sale talked to them directly, it would be stuffed with protocol code (low cohesion) and depend on every external API (high coupling).
  2. PV step 1: identify the point of instability. It is the different interfaces, or APIs, of the external tax calculators, including future ones that don't exist yet. This is a variation point: the current requirements already demand several.
  3. PV step 2a: Indirection. Put an adapter object in front of each calculator. Each adapter is a local software object that calls its external system through its native API, so Sale is shielded from the protocols. The adapters are also Pure Fabrications.
  4. PV step 2b: Polymorphism. getTaxes behaves differently for each calculator, so it becomes a polymorphic operation of the interface ITaxCalculatorAdapter, which every adapter implements. Sale now depends only on this stable interface (the dashed «use» arrow).
  5. The payoff. A new calculator means one new adapter class implementing the interface, with no change to Sale. In the lecture's words: indirection protects against variation of interfaces; polymorphism protects against variation of behaviours.

Library example. The requirement "a member may borrow videos as well as books" makes Book a known point of variation. PV puts a stable Item interface around it, and Polymorphism handles the type-specific behaviour (getDetail).

PV is the root principle

Data encapsulation, interfaces, polymorphism, indirection, standards, virtual machines, operating systems, configuration files: all are mechanisms for PV. The lecture summary: PV, Low Coupling and High Cohesion are the fundamental goals; the other six GRASP patterns are ways to achieve them. The mechanisms motivated by PV are these.

Core

Core mechanisms

Data encapsulation, interfaces, polymorphism, indirection, standards. Virtual machines and operating systems are complex indirections.
Data-driven

Data-driven designs

Read codes, values, class names, style sheets, property files or O-R mapping metadata from outside, so behaviour is "parameterised" at runtime.
Data-driven

Service lookup

Naming or lookup services (JNDI, UDDI) protect clients from where services are located. A special case of data-driven design.
Externalised

Interpreter-driven designs

Rule interpreters, script engines and VMs externalise the logic, which is read in and interpreted.
Meta

Reflective designs

Introspection, e.g. the Java beans Introspector or Method.invoke.
Syntax

Uniform access

Same syntax for field access and method call (C#, Eiffel, Ada), so fields can become methods without changing clients.
Standards

Standard languages

SQL protects against many varying query languages.
Types

Liskov Substitution Principle

Below.
Structure

Structure-hiding designs

In particular the Law of Demeter, below.

Liskov Substitution Principle (LSP) exam

Code written against a type T (an interface or abstract superclass) must keep working as expected when given any subtype or implementation S of T. Formally (Liskov 1988), S is a subtype of T if substituting an S object for a T object leaves the behaviour of every program written in terms of T unchanged. In the tax example, addTaxes must work whichever adapter it is passed:

public void addTaxes(ITaxCalculatorAdapter calculator, Sale sale) {
    List<TaxLineItem> taxes = calculator.getTaxes(sale);   // must work for EVERY implementation
}

Law of Demeter: "Don't Talk to Strangers" exam

This was one of the nine GRASP patterns in Larman's first edition. It was replaced by the more general PV because it is a special case of it: protection against changes in object structure. Within a method, send messages only to:

  1. this (self);
  2. a parameter of the method;
  3. an attribute of this;
  4. an element of a collection that is an attribute of this;
  5. an object created within the method.

Those objects are the familiars; objects reached indirectly are strangers. Traversing long paths couples the client to how objects are connected, and the further the path, the more fragile the code.

familiar (attribute) strangers (reached through others) this : Register :Sale :Payment :Account :AccountHolder conforming sale.getTenderedAmountOfPayment() slightly fragile sale.getPayment().getTenderedAmount() sale.getPayment().getAccount().getAccountHolder() more fragile
How far does the code reach? Each arrow below the chain shows which object a statement in Register ends up depending on. The conforming version asks the familiar (sale) to get the information and hide how it did so.
class Register {
    private Sale sale;
    void slightlyFragile() {
        Money amt = sale.getPayment().getTenderedAmount();               // talks to a stranger (Payment)
    }
    void moreFragile() {
        AccountHolder h = sale.getPayment().getAccount().getAccountHolder(); // even further
    }
    void conforming() {
        Money amt = sale.getTenderedAmountOfPayment();                   // familiar hides the structure
    }
}

To obey the law strictly, you add operations to the familiars that return the desired information and hide how they got it. That isn't always worth it: structure in stable libraries (Java's) or in mature systems seldom changes. It matters most in young systems, where the structure is still changing.

PV, information hiding and the Open-Closed Principle

These are essentially the same idea under three names.

  • Information hiding (Parnas 1972) means hiding design decisions that are difficult or likely to change from other modules. It is not a synonym for data encapsulation, which is only one technique for it.
  • The Open-Closed Principle (Meyer): modules should be open for extension (adaptable) and closed to modification that affects clients. "Closed with respect to X" means clients are unaffected if X changes. A class with private fields and public accessors is closed with respect to its field definitions but open to changing them; the tax adapters are closed with respect to their public interface (ITaxCalculatorAdapter) but open to private changes as external APIs evolve. "Module" means any software element: method, class, subsystem or application.

PV itself was named as a pattern by Cockburn (1996), but the idea is decades older.

Contraindications: speculative PV exam

Protecting an evolution point can cost more than simply reworking a simple, "brittle" design when the change actually comes. Larman's examples are an unneeded scripting interpreter in a pager system, and his own early "generalize-itis" of writing superclasses for future cases that never arrived.

Novice brittle designs: no protection where it's needed Intermediate overly general designs: "generalize-itis" Expert chooses with insight: cost of change × its likelihood pick your battles: protect realistic variation points, not every imaginable one
Larman's summary. More protection is not automatically better. The slides add that Polymorphism has the same contraindication.

Benefits: new variations are easy to add; new implementations don't affect clients; coupling is lowered, and so are the impact and cost of change. PV is related to almost every principle and pattern (polymorphism, interfaces, indirection, encapsulation, most GoF patterns). Pree calls variation and evolution points "hot spots".

Check yourselfInside Register.endSale(), which of these break the Law of Demeter? (a) sale.becomeComplete(); (b) sale.getPayment().getAmount(); (c) Payment p = new Payment(cash); p.getAmount(); (d) catalog.getProductDescription(id).getPrice().

(a) is fine: sale is an attribute. (b) breaks it: Payment is reached through Sale, a stranger. (c) is fine: an object created within the method. (d) breaks it: the ProductDescription returned by the catalog is a stranger. (Whether to fix (d) depends on how stable that structure is.)

Check yourselfA team adds a plug-in scripting engine to a simple pager system "in case the rules change one day". Which principle is being over-applied, and what is the counter-argument?

Protected Variations, applied speculatively to an evolution point (Larman's own example). Protecting it may cost more than reworking a simple design if the change ever comes. Pick your battles: balance the cost of change against its likelihood.

Check yourself"Information hiding just means making fields private." True or false?

False. Parnas meant hiding design decisions that are difficult or likely to change, which is PV. Data encapsulation (private fields) is only one technique for it.

Check yourselfIn the tax design, which mechanism protects Sale from the different APIs, and which from the different behaviour of each calculator?

Indirection (the adapters) protects against variation of interfaces; Polymorphism (getTaxes on ITaxCalculatorAdapter) protects against variation of behaviours. Together they give the stable interface that PV asks for.

In short

Find points of predicted variation (current variation points or speculative evolution points) and put a stable interface around them. PV is the root goal; encapsulation, interfaces, polymorphism, indirection, LSP and the Law of Demeter are its mechanisms, and it is the same idea as information hiding and the Open-Closed Principle. Don't protect against changes that won't realistically come.

4.9

How the Principles Fit Together

You have now met all nine. They are not independent rules: some are means to others, and some regularly disagree. This section maps how they relate, collects the standard conflicts, and links GRASP to the GoF patterns of Part VI.

The relationship map

The lecture shows the relationships as a diagram in which each arrow means "is a way to achieve".

Protected Variations Low Coupling High Cohesion Polymorphism Indirection Pure Fabrication Information Expert Controller Creator directly ROOT GOAL EVALUATIVE GOALS MECHANISMS ASSIGNMENT arrow = "is a way to achieve"
PV at the top, Low Coupling and High Cohesion as the evaluative goals, the other six as mechanisms. Read upwards: a Controller is a kind of Indirection, which lowers coupling, which protects against variation. Creator feeds Expert because creation goes to whoever has or holds the data.
PrincipleIs a way to achieveWhy
Low CouplingProtected VariationsFewer dependencies mean variation spreads less
PolymorphismLow Coupling (and PV directly)Clients depend only on the common interface
IndirectionLow CouplingAn intermediary removes the direct dependency
Pure FabricationLow Coupling and High CohesionMoves alien responsibilities out of domain classes
Information ExpertLow Coupling and High CohesionBehaviour stays with its data
ControllerIndirectionSits between the UI layer and the domain layer
CreatorInformation ExpertCreation goes to whoever has or holds the data

Conflicts and trade-offs exam

Principles often disagree, and the exam rewards naming the conflict and saying how it was resolved. Read each row from the two competing principles across to the resolution, and notice how often the deciding factor is cohesion, coupling or stability.

SituationOne principle saysAnother saysResolution
Save a Sale to the DBExpert: Sale has the dataHC/LC: SQL makes Sale incohesive and coupled to JDBC; duplicated in every class; mixes concernsPure Fabrication PersistentStorage (also an Indirection)
Create PaymentCreator: Register records Payments and has the amount tenderedLC: adds Register→Payment coupling. HC: Register drifts towards bloatSale creates it (it closely uses Payment). "By Creator and Low Coupling"
Compute line subtotalExpert: ProductDescription has the priceLC: then Sale must also know ProductDescriptionSalesLineItem (knows quantity and its description)
Compute balanceSale and Payment are both partial expertsLC: Payment would need new visibility to SaleSale.getBalance(), because Sale already sees its Payment
Monopoly "take a turn"Real world: a human takes a turnExpert: Player, MonopolyGame and Board each hold about a third of the infoPlayer, justified by HC (MonopolyGame already busy) and future evolution (cash, buying strategy), not by imitating humans
One controller for everythingController: a root/system object is validHC: many system events → bloatedUse-case controllers (OrderHandler)
Log completed salesLRG/Expert: Store knows its salesHC: Store grows incohesiveStore early on; SalesLedger (a real domain concept) when Store grows
UI shows running totalLC: UI talks only to Register, which forwards getTotalHC: Register's interface keeps growingUI may couple directly to Sale, because coupling to a stable class is fine
No coupling at allLC taken to the extremeOO metaphor / HCModerate coupling is normal; couple to stable things
Interfaces "just in case"PV / PolymorphismCost and complexityOnly at realistic variation points
Remote/performance-critical objectsHC: fine-grained classesPerformance NFRAccept coarser, less cohesive objects
Many helper classesPure Fabrication: cohesive helpersExpert/LC: data separated from behaviourKeep responsibilities in representational classes where Expert works
Larman's tie-breaking guideline

When there are alternatives, look closely at the cohesion and coupling of each and at likely future evolution, and choose the one with good cohesion, coupling and stability under likely change.

GRASP and the GoF patterns exam

The GRASP principles generalise the GoF patterns, so each GoF pattern can be described in GRASP terms. This is also how mixed GRASP/GoF multiple-choice options are built.

GoF pattern Indirection PureFabrication Polymorphism ProtectedVariations LowCoupling HighCohesion Adapter Factory(Concrete / Abstract): complex creation Façadeto a subsystem; a façade controller is one Observerpublisher ↔ subscribers, common listener Strategy, State, Composite, Command, Proxy, Decorator Bridge, Mediator All GoF patterns most
Read across a row to describe a GoF pattern in GRASP words. Adapter is the richest: an Indirection and a Pure Fabrication that uses Polymorphism to achieve PV against varying external interfaces (the lecture's description). Factory is the answer to Creator's contraindication (complex creation). A hollow dot means "most, not all".
Check yourselfCreator says Register should create Payment; the final design has Sale create it. Write the one-sentence justification an examiner wants.

"Sale creates Payment by Creator (Sale closely uses Payment and has the initialising data) and Low Coupling: Register then never needs to know Payment, whereas Register-creates-Payment would add a Register→Payment dependency and push Register towards bloat (High Cohesion)."

Check yourselfDescribe the Observer pattern in GRASP terms.

It is an Indirection giving Low Coupling between publisher and subscribers, and it uses Polymorphism through a common listener interface. (Like every GoF pattern it is also a Pure Fabrication.)

Check yourselfWhy is Controller drawn as a way to achieve Indirection on the map?

Because a controller sits between the UI layer and the domain layer: the UI depends on the controller instead of directly on many domain objects, which is exactly what an intermediary does.

In short

PV is the root goal; Low Coupling and High Cohesion are the evaluative goals; the other six are ways to achieve them. When principles conflict, compare cohesion, coupling and stability under likely change, and say which principle won and why. Every GoF pattern can be described in GRASP words.

4.10

Worked Use-Case Realisations (Larman ch. 18) exam

Larman's chapter 18 puts all the principles to work on complete use cases. This is exactly what an exam design question asks you to do: take a system operation and draw the design sequence diagram, justifying each message. Here is the general procedure, then NextGen POS and Monopoly.

The procedure for designing a system operation

  1. Take the system operation from the SSD. By Controller, choose the domain object that receives it, and draw the found message into that object.
  2. Work through the operation contract postconditions (Part II). An instance creation calls for Creator. An association formed is usually done by the creator, or by whoever has visibility. An attribute modification calls for Expert: the object that owns the attribute.
  3. For every other responsibility, state it as a question ("Who knows X?") and apply Expert. Tabulate the information needed against the classes that have it.
  4. Evaluate the alternatives with Low Coupling and High Cohesion, and then with future evolution (PV).
  5. If Expert's choice hurts cohesion or coupling (technical services, generic behaviour), use Pure Fabrication or Indirection. If behaviour varies by type, use Polymorphism.
  6. Check visibility for every message: attribute, parameter, local or global (Part III).
  7. Ignore display and output (Model-View Separation); just make sure the information is known.
  8. Design Start Up last. Once you know what must exist, pick an initial domain object at or near the root of the containment hierarchy (Store, MonopolyGame). It creates its children by Creator.
  9. Annotate messages with the principle used ("by Creator", "by Expert", …) and update the DCD.

NextGen POS: Process Sale

The controller is Register, a façade device controller. That is reasonable because there are only four system operations: makeNewSale, enterItem, endSale and makePayment. (In UML the system operation is a found message arriving from outside the diagram, drawn from a filled dot.)

makeNewSale() endSale() :Register makeNewSale() create() by Creator :Sale Sale then creates its empty lineItems list (Creator) :Register :Sale endSale() becomeComplete() by Expert: Sale owns isComplete getBalance() s : Sale :Payment bal = getBalance() amt = getAmount() t = getTotal() by Expert and Low Coupling: Sale already sees its Payment; bal = amt − t
Three short operations. makeNewSale: the Register records Sales, so it creates them (Creator). endSale: setting isComplete is an attribute modification, so it goes to its owner (Expert). getBalance is not a system operation, but any message can start its own interaction diagram; getTotal is designed as in 4.3.
enterItem(id, qty), message by message
:Register enterItem(id, qty) by Controller :ProductCatalog desc = getProductDescription(id) by Expert :Sale makeLineItem(desc, qty) create(desc, qty) by Creator sl : SalesLineItem lineItems.add(sl)
  1. Controller. The system operation enterItem(id, qty) from the SSD arrives as a found message at :Register, the façade controller. Register will coordinate, not do the work.
  2. Find the description, by Expert. Register asks :ProductCatalog for desc = getProductDescription(id): the catalog contains all the descriptions. Register can send this message because it has permanent attribute visibility to the catalog, set up at Start Up.
  3. Delegate to the Sale. Register sends makeLineItem(desc, qty) to the current :Sale, which it knows through its currentSale attribute. The contract's postconditions (a line item created and associated with the sale) are about the sale's contents, so the sale should handle them.
  4. Create the line item, by Creator. Sale contains (aggregates) its line items, so Sale creates sl : SalesLineItem, passing the description and quantity as initialising data. The create arrow points at the new object's box.
  5. Form the association. Sale adds sl to its lineItems collection, completing the "association formed" postcondition. Done by the creator, which already has visibility to the new object.
makePayment(cashTendered), message by message
:Register makePayment(cashTendered) by Controller s : Sale makePayment(cashTendered) create(cashTendered) by Creator and Low Coupling :Payment :Store addSale(s) by Expert
  1. Controller. makePayment(cashTendered) arrives at :Register, the same controller as for every other Process Sale operation, so it can enforce the order (no payment before endSale).
  2. Delegate. Register forwards makePayment(cashTendered) to the current sale s. It does not create the payment itself.
  3. Create the Payment, by Creator and Low Coupling. Sale creates :Payment, passing the cash tendered. Sale closely uses its Payment, and choosing Sale rather than Register adds no new coupling (4.4).
  4. Log the sale, by Expert (and LRG). Register sends addSale(s) to :Store, because the store knows its completed sales. (If Store grew incohesive, a SalesLedger, a real domain concept, could take over.) Finally, the balance is computed by Sale.getBalance() as shown above.

Putting the four operations together gives this design class diagram. Every method in it was put there by one of the decisions above.

Store -name: Text-address: Address +addSale(s: Sale) Register +makeNewSale()+enterItem(id: ItemID, qty: Integer) +endSale()+makePayment(cash: Money) Sale -isComplete: Boolean-time: DateTime +becomeComplete()+makeLineItem(desc: ProductDescription, qty: Integer) +makePayment(cash: Money)+getTotal(): Money+getBalance(): Money ProductCatalog +getProductDescription(id: ItemID): ProductDescription SalesLineItem -quantity: Integer+getSubtotal(): Money Payment -amount: Money+getAmount(): Money ProductDescription -description: Text-price: Money-itemID: ItemID +getPrice(): Money register1 completedSales* currentSale1 catalog1 catalog1 lineItems1..* payment1 descriptions1..* description1
The NextGen DCD after iteration 1. Methods trace back to decisions: Register's four are the system operations (Controller); makeLineItem and makePayment on Sale are Creator; getTotal, getSubtotal, getPrice, becomeComplete, getBalance and addSale are Expert. Each navigable arrow exists because some message needed that visibility.

Connecting the UI to the domain

In main, you create the initial domain object Store, get its Register, and pass that to the window: new ProcessSaleJFrame(store.getRegister()). Alternatively the UI gets the domain object from a factory. To show the running total, the UI has two options. It can ask the Register, which keeps UI coupling lower but makes Register bigger and less cohesive. Or it can get the Sale and ask it directly: more coupling, but acceptable because Sale is stable. Larman takes the second option.

Start Up: designed last
:Store create() pc = create() by Creator pc : ProductCatalog loop [for each product] pd = create(id, price, descr) pd : ProductDescription descriptions.put(id, pd) create(pc) by Creator :Register main: new ProcessSaleJFrame(store.getRegister())
  1. Pick the initial domain object. Start Up is designed last, once you know what must exist. Store sits at the root of the containment hierarchy, so it is created first.
  2. Store creates the catalog, by Creator. The store contains the product catalog.
  3. The catalog loads its descriptions, by Creator. For each product, the catalog creates a ProductDescription and puts it in its descriptions map. It contains them, so it creates them.
  4. Store creates the Register, passing the catalog. create(pc) gives the Register permanent attribute visibility to the catalog, which enterItem needed. Note that multiplicities in the design may differ from the domain: the software Store creates one Register.
  5. Hook up the UI. main passes the store's Register to the window, so every UI event goes to the controller.

Monopoly: Play Monopoly Game

Here the controller is MonopolyGame, a root-object façade, which works because there are only two system operations. The design proceeds in three decisions.

The game loop. The loop is "for N rounds: for each player p: p takes a turn". By Expert, MonopolyGame runs it, because it knows the round count (LRG) and all the players. A private helper playRound() keeps the methods cohesive and uses domain vocabulary.

Who takes a turn? This is the course's main example of partial experts with none dominant.

Who should take a turn? Playerknows its current locationpartial expert MonopolyGameholds the dicepartial expert Boardholds all the squarespartial expert Player wins: MonopolyGame is already busy (High Cohesion), and under the full rules a turn also involves the player's cash and buying strategy (future evolution). Not "because humans take turns": copying human roles would make a POS Cashier do everything.
No dominant expert, so use the tie-breakers. Compare cohesion and coupling, then likely future evolution. The real-world analogy is never the justification.

Inside takeTurn. Die rolls itself, by Expert, since it changes its own faceValue. Board.getSquare(oldLoc, fvTot) finds the new square, by Expert, since Board knows all the Squares. The Piece (or Player) updates the location. Player coordinates all of this, so it needs permanent visibility to the dice, Board and Piece, set up at Start Up.

playGame(), iteration 1
:MonopolyGame playGame() by Controller loop [rnd < N] playRound() players[i] : Player loop [each p in players] takeTurn() by Expert dice[i] : Die loop [for each Die in dice] roll() fv = getFaceValue() :Piece oldLoc = getLocation() :Board newLoc = getSquare(oldLoc, fvTot) setLocation(newLoc)
  1. Controller. playGame() arrives at :MonopolyGame, a root-object façade controller: fine, because Monopoly has only two system operations.
  2. The game loop, by Expert. The game knows the number of rounds and all the players, so it runs loop [rnd < N], calling its private helper playRound() (method-level cohesion, domain vocabulary).
  3. Each player takes a turn. Inside playRound, the game sends takeTurn() to each player. Player was chosen from three partial experts using High Cohesion and future evolution, as in the figure above.
  4. Roll the dice, by Expert. Each Die changes its own faceValue, so it rolls itself; the player then asks for the face value and sums fvTot. (Iteration 2 replaces this loop with the Cup, 4.7.)
  5. Where am I? In iteration 1 the :Piece knows the location, so the player asks it: oldLoc = getLocation().
  6. Find the new square, by Expert. :Board knows all the squares, so newLoc = getSquare(oldLoc, fvTot) goes to the board.
  7. Move. The player tells the piece setLocation(newLoc). Because Player keeps asking Piece for its data, iteration 2 moves location into Player, drops Piece, and ends the turn with loc.landedOn(this) (Polymorphism, 4.6).

Monopoly Start Up. MonopolyGame creates the Board and the Players (and the dice or the Cup), and Board creates the 40 Squares, all by Creator. Larman shows this compactly with «create» dependencies in a class diagram.

MonopolyGame Board Player Cup (or Dice) Square «create» «create» «create» «create»
Start Up in one picture. Each dashed «create» arrow is a Creator decision: the game contains (or has the initialising data for) the board, players and cup; the board compositely aggregates the squares.
Command-Query Separation (ch. 18)

Every method is either a command, which changes state and returns void, or a query, which returns data and has no side effects, but never both. That is why Die.roll() is void and getFaceValue() is separate (and likewise Cup.roll() and Cup.getTotal()). The benefit is predictable code: a getter never surprises you by changing anything.

Check yourselfThe operation contract for enterItem says: a SalesLineItem instance sli was created; sli was associated with the current Sale; sli.quantity became quantity; sli was associated with a ProductDescription. Which principle handles each postcondition?

Instance creation: Creator (Sale contains line items). The two associations formed: done by the creator, which has visibility (Sale adds sl to lineItems; the description is passed into create(desc, qty)). The attribute modification (quantity): set by the object that owns it, during creation, i.e. Expert.

Check yourselfSpot the error: a student's enterItem diagram has :Register send create(desc, qty) to :SalesLineItem and then addLineItem(sli) to :Sale.

It ignores Creator: the Sale contains the line items, so Sale should create them (via makeLineItem(desc, qty)). Register creating them adds a Register→SalesLineItem dependency (worse Low Coupling) and gives the controller work it should delegate (worse High Cohesion).

Check yourselfWhy is Start Up designed last, and why does Register's constructor take the catalog?

Only after designing the system operations do you know which objects must exist and which permanent visibilities are needed. enterItem needs Register to send getProductDescription to the catalog, so Start Up passes the catalog into create(pc), giving Register attribute visibility to it.

In short

Design each system operation separately: Controller for the found message, Creator and Expert for the contract's postconditions, Low Coupling and High Cohesion to choose between alternatives, Pure Fabrication, Indirection and Polymorphism when Expert backfires. Check visibility, ignore display, design Start Up last, and label each message with its principle.

4.11

Course Examples and Workshop Solutions

The lectures and workshops apply the same reasoning to three more systems. They are worth knowing because exam questions are built the same way: a small domain, then "who should do X, and why?".

The Library Borrowing System (lectures, weeks 4–5)

BorrowingKiosk Category Book lists ▸ groups ▸ BorrowingRecord records ▾ Member borrowLimitstatusexpirationDate ◂ has BorrowedItem contains ▾ 1..* described by ▸
The library domain model (no methods, no arrows). A kiosk lists categories of books and records borrowing records; a member has records, each containing borrowed items described by books.

The lectures ask a sequence of design questions about it:

  • Who creates a BorrowedItem? BorrowingRecord, by Creator: it contains (compositely aggregates) them.
  • Who checks whether a member has reached the borrowing limit? Member.hasReachedLimit(), by Expert: Member has borrowLimit and is associated with its records.
  • Why not BorrowingKiosk or BorrowingRecord? Both are acceptable, but each costs more, as the graphs show.
Kiosk.hasReachedLimit() Record.hasReachedLimit() Member.hasReachedLimit() Kiosk Member BorrowingRecord new higher coupling (new Kiosk → Member); a busy kiosk loses cohesion Kiosk Member BorrowingRecord needs limit higher coupling: the record must reach the member's borrowLimit Kiosk Member BorrowingRecord lowest coupling; kiosk stays cohesive; Member acts as an Indirection
Several designs satisfy GRASP; LC and HC choose between them. The Member design needs no new associations, keeps the busy kiosk cohesive, and makes Member an intermediary between kiosk and records.
  • The kiosk is the controller; who does the application logic? No domain class fits without hurting High Cohesion or Low Coupling, so use the Pure Fabrication BorrowingHandler (drawn in 4.7). The kiosk keeps the UI-facing memberLogin, listItem, returnItem and newBorrowing, and delegates.
  • Future: videos as well as books. Apply PV at the known variation point Book, with a stable Item interface (getTitle, getDetail, getQuantity) implemented by Book and Video. getDetail is polymorphic, and BorrowingItem refers to Item.

The lecture's closing note: several designs can satisfy GRASP, so use Low Coupling and High Cohesion to choose between them.

Workshop 4: online marketplace

The domain has User, Listing, Item, Category, SubCategory, Bid, Transaction, Message, Photo and Address. The partial solution reasons as follows.

QuestionAnswerPrinciple and reason
Who finds the highest bidder?ListingExpert: it has all the bids and their users
Who lists all items in a subcategory?SubCategoryExpert: most direct access, rather than scanning all Items
Who knows a user's past transactions?UserExpert: knows both its bought and its sold transactions
Who creates a Bid?ListingCreator: closely uses and aggregates bids, and has most of the initialising data. User has the bidder but doesn't use the bid afterwards
Who creates a Transaction?ListingCreator: has all the initialising data (the listing, the buyer, who is the highest bidder, and the seller) and can "finalise itself"
User buyer or seller? Listing Bid User Transaction coupled to three classes; transaction logic spread over three; duplicated, ambiguous creation
User as creator. Which User, buyer or seller? Either way User is coupled to Listing, Bid and User, and transaction behaviour is spread over three classes (lower cohesion).
Listing Bid User Transaction already known create has all the initialising data, already knows bids and users; behaviour stays together
Listing as creator. The behaviour stays in Listing and Transaction, and there is one obvious creator. Avoid duplicated creation logic and ambiguous control flow.

Controller. The controllers offer createListing(...) and makeBid(...), taking all the user input as parameters. Use one controller if Listing owns both behaviours; if the behaviours are split between Listing and User, use two use-case controllers, which keeps cohesion and separates concerns. The workshop's lesson: GRASP principles are not mutually exclusive, and every choice is a trade-off you must justify.

Workshop 5: Mobile Service Terminal (MST) POS

The indicative solution maps onto GRASP like this.

Design elementGRASP reading
MST with makeSale(): Sale, scan(barcode): Item, processPayment(cardData): boolean, checkStock, checkSalesA device façade controller, like Register
MST creates SaleCreator: it records currentSales
Sale.calculatePrice()Expert
Abstract Card (CreditCard, StoreCard); abstract CardAgency with validate and charge (VisaAgency, StoreCardAgency)Polymorphism and PV for the card types and the external agencies
SalesServer, SecurityServer.releaseSale(Sale), StockInventoryServerIndirections to external systems

The worksheet stresses iterating: dynamic modelling reveals missing methods and attributes, so you update the DCD to match.

Tony's Pizza (weeks 4–5) is covered under each principle: Creator (4.2), Expert (4.3), the OrderHandler use-case controller (4.5) and the Item.getPrice() polymorphism (4.6).

Check yourselfIn the marketplace, why is Listing a better creator of Bid than User, even though the User is the bidder?

Creator: Listing closely uses and aggregates its bids and has most of the initialising data. The User supplies the bidder but doesn't use the bid afterwards, so making it the creator would add coupling without a containment or usage relationship to justify it.

Check yourselfIn the MST solution, a new card type (say, a gift card) must be supported. Which design elements make that cheap, and which principles are they?

The abstract Card (and, for its external processor, the abstract CardAgency with validate/charge). Adding GiftCard (and a matching agency) is new subclasses with no change to MST or Sale: Polymorphism as the mechanism, Protected Variations as the goal.

In short

Library: BorrowingRecord creates BorrowedItems (Creator), Member checks the limit (Expert; also an Indirection), BorrowingHandler holds the logic (Pure Fabrication), Item protects against videos (PV + Polymorphism). Marketplace: Listing finds the highest bidder and creates Bids and Transactions. MST: a device façade controller, polymorphic cards and agencies, server indirections.

4.12

Exam Toolkit exam

This last section turns the Part into exam technique: a cheat sheet for the multiple-choice questions, a template for written justifications, and the mistakes that cost marks.

Decision cheat sheet for MCQs

Match what the question stem describes to the left column. Several rows warn that a more specific GoF pattern beats the nearest GRASP answer.

If the question describes…Pick
"Who should create X?": a container, aggregate, recorder, or the class with the initialising dataCreator
Creation is complex or conditional (choose one of a family of classes, pooling, config-driven)Factory (GoF), not Creator
"Where should this new feature/responsibility go?", "how should he start?", "which class knows X?"Information Expert
A button, GUI event or external request must reach the back end/domain; "first object to receive a system event"; UI must not contain logicController
One handler class receives all requests and does too muchController (bloated controller → use-case controllers + delegation). If the option is phrased as the problem: Low Cohesion
A class with many unrelated methods, a "dumping ground", hard to understand/maintain/reuseLow Cohesion (the problem) / High Cohesion (the principle)
Changes ripple to many classes; too many dependencies; "reduce impact of change"; evaluating two designsLow Coupling
Behaviour differs by type or by the role an object plays; replace if/switch on type; pluggable alternativesPolymorphism (the official answer to 2021 S2 Q1.1, a person whose behaviour changes with their role). Prefer Strategy only if the stem describes interchangeable algorithms for one context object, State if behaviour changes with state
Need a helper/service class that is not a domain concept to keep domain classes clean (persistence, dice cup, generic service)Pure Fabrication
Put an intermediary between A and B so they are not directly coupledIndirection, unless a more specific GoF intermediary fits: Adapter (different interfaces), Façade (simplify a subsystem), Observer (event notification)
Protect the system from a known or likely change; "stable interface"; future third-party systemsProtected Variations
One simple entry point to a complex existing subsystemFaçade (GoF), not Controller
Several external systems with different interfacesAdapter (GoF); in GRASP terms Indirection + Polymorphism + PV

The tie-break rule

The options mix GRASP and GoF names, so decide first which family the stem is about.

Read the stem a specific GoF structure? yes Pick the GoF pattern recursive part–whole tree → Composite stackable add-ons → Decorator front for a subsystem → Façade different interfaces → Adapter no who gets a responsibility, or a quality? yes Pick the GRASP principle who creates, knows or handles an event, or a quality: coupling, cohesion
Structure beats responsibility. GRASP names appear as distractors in GoF questions: Information Expert in the Composite question, High Cohesion or Controller in the Façade question, Indirection or Low Coupling in the Decorator question.

Past-exam MCQs. All 20 items from 2021 are worked in Part IX. The GRASP ones are S1 Q1.1 (Low Cohesion), S2 Q1.1 (Polymorphism, per the official answer), S2 Q1.2 (Controller), S2 Q1.5 (Information Expert) and S2 Q1.10 (Controller).

How to justify a design choice in writing

A justification earns marks when it names the principle and gives specific evidence. Build each one from these parts.

1 RESPONSIBILITY[what is done or known] 2 IS ASSIGNED TO[Class] 3 BY[Principle] 4 BECAUSE [CLASS] …[specific evidence: see below] 5 THIS ALSO SUPPORTS[Low Coupling / High Cohesion / PV] because … 6 THE ALTERNATIVE[Other class] was rejected because … Valid evidence: has attribute X · aggregates/contains Y · records Y · has the initialising data · receives the system operation · its behaviour varies by type
Principle + evidence + trade-off. "This is good design" earns nothing; "Sale aggregates its SalesLineItems" does.

Model justifications in that style:

Model answers
  • "By Information Expert, Sale is responsible for getTotal() because it aggregates all its SalesLineItems, the information needed to sum the subtotals. Each SalesLineItem computes getSubtotal() as the expert on its quantity and its ProductDescription."
  • "By Creator, Board creates the Squares because it compositely aggregates them. No coupling is added, since Board must reference the Squares anyway."
  • "By Controller, MonopolyGame (a façade controller representing the root object) receives playGame from the UI. This is acceptable because there are only two system operations, so it will not become bloated. It delegates turns to Player, keeping High Cohesion."
  • "Sale rather than Register creates Payment (Creator: Sale closely uses Payment). This keeps coupling low, because Register need not know Payment, and keeps Register cohesive."
  • "PersistentStorage is a Pure Fabrication. Saving belongs to no domain concept; putting it in Sale (as Expert suggests) would make Sale incohesive and coupled to JDBC. The fabrication is cohesive and reusable, and acts as an Indirection between domain and database."
  • "ITaxCalculatorAdapter applies Protected Variations at the known variation point of external tax-calculator APIs. Adapters give Indirection, and getTaxes is polymorphic, so a new calculator means adding one class without changing Sale (OCP)."

On diagrams, label messages and classes with the principle ("by Creator", "by Expert", "by Polymorphism"), as Larman and the lecturers do. The project rubrics (written by the same teaching team) reward "correct identification of design concerns using GRASP" and justification with specific references to classes, methods and responsibilities. They also say that a well-justified design based on correct principles is sufficient: it need not be "the best". Vague "this is good design" statements earn nothing.

Common mistakes

Mistakes that lose marks
  • Assigning responsibilities the way people do the job. A Cashier object that does everything, or Player.takeTurn justified by "humans take turns". Justify by Expert, coupling and cohesion instead.
  • Confusing domain and design classes. Creator and Expert apply to software classes. The domain model is inspiration, not a 1:1 template: classes can be added (fabrications), removed (Piece), or have different multiplicities.
  • UI objects handling system events. A window should not send Sale.makeLineItem itself, and the MVC/UI controller is not the GRASP controller.
  • Controllers doing the work. Business logic inside Register or OrderHandler, or one façade controller for dozens of system events.
  • Testing types with if/switch. Use polymorphic operations. In code the corollary forbids instanceof dispatch; an alt frame in a diagram only documents the polymorphic cases.
  • Using Pure Fabrication as an excuse for new classes. "Manager" classes that take all the behaviour away from the data and leave anaemic domain objects.
  • Speculative generality. Interfaces and polymorphism at points that will never vary.
  • Treating Low Coupling as "no coupling", or worrying about coupling to stable library classes.
  • Duplicated or ambiguous creation. Two classes able to create the same object, such as the buyer and the seller User creating a Transaction.
  • Expert applied blindly to technical services. Domain classes saving themselves to the DB, or talking TCP to external systems.
  • Calling Controller and Façade the same thing in an MCQ. A façade controller handles system events from the UI; GoF Façade simplifies access to a subsystem.
  • Treating information hiding as data encapsulation. Parnas meant hiding design decisions that are likely to change, which is PV.
  • Unjustified answers. Naming a principle without the evidence (attribute, association, aggregation), or without saying what was traded off.
Check yourself"A developer needs to add a 'loyalty points' calculation to the POS. Where should he start?"
  1. Controller
  2. Information Expert
  3. Indirection
  4. Pure Fabrication

B, Information Expert. "Where should this new responsibility go / how should he start?" is the Expert cue: find the class that has the information needed (e.g. the Sale's total and the customer's history) and give it the job.

Check yourself"An application must work with three payment gateways that each expose a different API, and more may be added later. Which is the best answer?"
  1. Indirection
  2. Controller
  3. Adapter
  4. High Cohesion

C, Adapter. Several external systems with different interfaces is the specific GoF structure, so the tie-break rule picks the GoF pattern. In GRASP terms it is Indirection + Polymorphism + PV, which is why Indirection is a tempting distractor.

Check yourselfImprove this exam justification: "Sale creates Payment because it is good design and follows GRASP."

It names no principle and gives no evidence. Better: "By Creator, Sale creates Payment because Sale closely uses its Payment and has the initialising data (it knows the total). This supports Low Coupling: Register never needs to know Payment. The alternative, Register (which records payments), was rejected because it adds a Register→Payment dependency and makes Register less cohesive."

Check yourself"The system must give clients a single simple entry point to a complex legacy billing subsystem." Controller or Façade?

Façade (GoF). One simple entry point to a complex existing subsystem is Façade's structure. A (façade) controller is about receiving system events from the UI layer; Controller is a distractor here.

In short
  • Match the stem's cue to a principle; if it describes a specific GoF structure, pick the GoF pattern.
  • Justify with principle + specific evidence + trade-off, and label diagram messages "by X".
  • Avoid the classic traps: human-role reasoning, UI handling events, controllers doing work, type switches, gratuitous fabrications and speculative interfaces.