Part VI

Design Patterns I: Façade to Singleton

Design patterns are named, reusable answers to design problems that keep coming back. This Part covers what a Gang of Four pattern is and how the exam tests patterns, then six of the patterns the course teaches, one at a time: Façade, Decorator, Builder, Adapter, the Factory family and Singleton. Patterns are worth roughly a third of the exam marks.

  • You willrecognise each pattern from the wording of an exam scenario, and say why it fits
  • You willdraw each pattern's class diagram, with every role in the right place and the right UML arrows
  • You willwrite and read the Java for each pattern, including usage code that talks only to the abstract type
  • You willjustify a pattern with GRASP (Protected Variations, Low Coupling, Indirection…) and name its trade-offs
6.1

Foundations: Patterns, GoF and the Exam exam

Experienced designers keep meeting the same problems: "these three services do the same job through different APIs", "this object needs optional extras", "there must be only one of these". Rather than re-invent a solution each time, they reuse one that is known to work and give it a name. This section explains what such a named solution is, where the famous list of 23 comes from, how patterns connect to the GRASP principles of Part IV, and how to write about a pattern so that it earns marks.

Why this Part matters

Patterns are worth roughly a third of the 120 exam marks, spread over several questions:

  • Q1: ten multiple-choice questions, each asking which GRASP or GoF pattern fits a scenario;
  • Q7: list the GoF patterns used in some given code;
  • Q8 (Semester 1) and Q3 (Semester 2): "describe this Java class", which means naming the pattern, giving an application and writing usage code;
  • Q9: draw a design class diagram using Composite (covered in Part VII).

Each pattern below is presented the way you will meet it in the exam: first the problem in scenario words, then the structure, the code, the course examples, the link to GRASP and the traps.

How to read the diagrams on this page

Every pattern is a cast of roles: someone who calls, an abstraction that hides the variety, the new class the pattern introduces, and the existing classes doing the real work. So that you can spot the same role across different patterns, every diagram on this page (and in Part VII) colours the roles the same way, and the prose uses matching coloured names such as Client or Adapter.

Clientr1the caller: it uses thepattern and sees as littleas possibleAbstractionr4the interface or abstractclass the client programsagainst (Target, Component)Key participantr2the class the pattern adds:Façade, Decorator, Builder,Adapter, Factory, SingletonConcrete / existingr3adaptees, cores beingwrapped, subsystem classes,concrete productsAnything extrar5supporting roles such asthe Builder's Director
The role colours. blue calls, violet is the abstract type the caller depends on, red is what the pattern adds (including the pattern's own abstract base class, such as the abstract Decorator), green is what already exists or is concrete, and gold is anything else. Colour is only a reading aid: in the exam, draw plain UML.

What a design pattern is

Definition · Pattern (Larman ch. 17, 26)

A pattern is a named problem/solution pair that can be applied in new contexts, together with advice on how to apply it and a discussion of its trade-offs.

The name matters as much as the solution. Because each pattern has a name, designers gain a shared vocabulary and can say a lot in a few words. Larman's example sentence is "let's use Adapters generated from a Singleton Factory". To anyone who knows the patterns, those seven words describe three cooperating designs, which you will meet in 6.5, 6.6 and 6.8, and see working together at the end of this Part.

The Gang of Four and their 23 patterns

GoF stands for the "Gang of Four": Gamma, Helm, Johnson and Vlissides, who wrote Design Patterns: Elements of Reusable Object-Oriented Software (1995). The book describes 23 patterns, originally illustrated in C++ and Smalltalk, and sorts them into three categories according to what they are concerned with. The exam sometimes asks for a pattern's category, so learn which column each taught pattern sits in.

Creational (5)abstracting how objectsare instantiatedAbstract Factorybrief · Part VIBuildertaught · Part VIFactory Methodbrief · Part VIPrototypeSingletontaught · Part VIStructural (7)how classes and objects arecombined into larger structuresAdaptertaught · Part VIBridgeCompositetaught · Part VIIDecoratortaught · Part VIFaçadetaught · Part VIFlyweightProxybrief · Part VIIBehavioural (11)communication between objects;assigning responsibilitiesChain of ResponsibilityCommandbrief · Part VIIInterpreterIteratorMediatorMementoObservertaught · Part VIIStatebrief · Part VIIStrategytaught · Part VIITemplate Methodtaught · Part VIIVisitor(Simple / Concrete) Factorytaught · Part VINOT one of the 23. Larman calls it asimplification of Abstract Factory.
All 23 GoF patterns, by category. Blue: the patterns this course teaches, with the Part that covers them. White: patterns Larman covers briefly (Abstract Factory and Factory Method in 6.7; Proxy, State and Command in Part VII). Dashed: not in the course. The gold card is the odd one out: the course also teaches (Concrete/Simple) Factory, which is not one of the 23.

A quick way to remember the categories: creational patterns answer "how does this object get made?", structural patterns answer "how are these objects wired together?", and behavioural patterns answer "who does what, and how do they talk?". In this Part, Façade, Decorator and Adapter are structural, while Builder, the Factory family and Singleton are creational.

GRASP is the "alphabet" behind GoF exam

The GRASP principles of Part IV are general advice about assigning responsibilities. Larman argues that most design patterns are just specialisations of a few GRASP principles. That is useful in the exam: if you can name the GRASP principles a GoF pattern relies on, you can justify the pattern in any written answer. Larman makes four general claims.

  1. Every GoF pattern is a Pure Fabrication. In his words, "All GoF design patterns … are Pure Fabrications": each one invents a class that is not a domain concept (no shop has a "ServicesFactory").
  2. Adapter, Façade and Observer specialise Indirection: they put an intermediate object between two others so that they are not directly coupled.
  3. Adapter, Command, Composite, Proxy, State and Strategy rely on Polymorphism: several classes share one interface, and the caller doesn't care which it gets.
  4. Almost every pattern exists to provide Protected Variations (PV), mainly through Low Coupling: it builds a stable interface around a point that is likely to change.
Pure FabricationLarman: “All GoF design patterns … are Pure Fabrications”, i.e. invented classes, not domain conceptsIndirectionPolymorphismFaçadeone point of contactAdapterObserverDecorator*StrategyCompositeTemplate MethodStateCommandProxyFactoryBuilder*Singletoncreational:Pure Fabrication+ cohesionalmost all of them exist to give Protected Variations, mainly via Low Coupling
Where each pattern sits. The placement follows the pattern-by-pattern list in the table below, which is why Observer and Decorator sit in the overlap (Larman's headline lists name Observer only under Indirection). Patterns marked * are ones Larman does not cover; their entries are reasoned from the course slides and GoF.

Pattern by pattern, the GRASP principles each one applies are as follows. Where Larman gives wording, it is his. You don't need to memorise every cell; aim to be able to give two principles for any pattern.

PatternGRASP principles it applies
Adapter"supports Protected Variations with respect to changing external interfaces or third-party packages through the use of an Indirection object that applies interfaces and Polymorphism". Also a Pure Fabrication.
FactoryPure Fabrication. High Cohesion through separation of concerns; PV when the class to create is data-driven.
SingletonGives global visibility to one instance: an alternative to attribute or parameter visibility (see Part III).
FaçadeIndirection, giving Low Coupling (outsiders couple to one point). PV against changes inside the subsystem.
StrategyPolymorphism, giving PV with respect to changing algorithms. The strategies are Pure Fabrications.
CompositePolymorphism. PV, because the client is unaffected by whether an object is atomic or composite.
ObserverPolymorphism plus Indirection through an interface, giving Low Coupling (Model–View Separation). PV, because the publisher doesn't know the class or number of its subscribers.
Decorator*Polymorphism and Indirection. PV, since features are added without editing existing classes; High Cohesion, with one decorator per feature.
Builder*Pure Fabrication. High Cohesion, because construction is separated from use; PV over representations.
Template MethodPolymorphism through hook methods. PV, because the invariant skeleton is protected.

* Larman does not cover Decorator or Builder, so those two rows are reasoned from the course slides and GoF.

How to write about a pattern in the exam exam

Questions such as "describe this Java class" or "which pattern would you use, and why?" reward a fixed shape of answer. Follow the same five steps every time, and you will not forget a part that carries marks.

  1. Name the pattern and its category ("Adapter, a structural GoF pattern").
  2. State the problem in the scenario's terms, not in textbook terms: "several tax calculators with different APIs that we cannot change".
  3. Give the solution and roles by mapping every pattern role to a concrete class in the question: "ITaxAmount = Strategy interface; PercentTaxAmount = ConcreteStrategy; Employee = Context".
  4. Explain why it helps by naming GRASP principles (PV, Low Coupling and so on), plus one trade-off.
  5. If asked, give a usage code fragment that compiles and shows the client using only the abstract type.

UML notation used with patterns

Pattern diagrams lean on a handful of UML conventions that are easy to get subtly wrong, and markers notice. The numbered badges are explained below the figure.

«interface»ITaxCalculatorAdapter+getTaxes(s: Sale): List<TaxLineItem>TaxMasterAdapterSquare+landedOn(p: Player)RegularSquareServicesFactory1-instance: ServicesFactory+getInstance(): ServicesFactory+getAccountingAdapter(): IAccountingAdapterRegister«interface»IAccountingAdapteraccountingAdapter1:Register:ServicesFactory1getAccountingAdapter()123456
The six notation details you need for pattern diagrams, drawn with classes from the NextGen POS and Monopoly examples.
  1. Interfaces and realisation. An interface carries the «interface» keyword. A class that implements it is joined by a dashed line with a hollow triangle (in Java, implements).
  2. Abstract classes and subclassing. An abstract class or method has an italic name, or is marked {abstract}. Subclassing (extends) is a solid line with a hollow triangle.
  3. Singleton marker. A singleton class may show a "1" in the top-right corner of its name compartment.
  4. Static members are underlined, such as a singleton's instance field and getInstance() method.
  5. Point at the interface. Associations and attribute types should target the interface, not a concrete class, so that any implementation can be plugged in.
  6. A lifeline marked "1" means the object was reached through Singleton, so the getInstance() call is implicit and not drawn.

One more convention is a matter of style: Larman's guideline is to put the pattern name in the class name (TaxMasterAdapter, ServicesFactory, CompositeBestForCustomerPricingStrategy), because it tells readers immediately which pattern is in play.

Check yourselfWhich GoF category does each belong to: Decorator, Builder, Façade, Singleton, Adapter? And which pattern taught in the course is not one of the GoF 23 at all?

Structural: Decorator, Façade, Adapter (they are about how objects are wired together). Creational: Builder and Singleton (they are about how objects are made). The odd one out is (Simple/Concrete) Factory: Larman calls it "not a GoF design pattern, but extremely widespread", a simplification of Abstract Factory.

Check yourselfAn exam answer reads: "I would use Adapter because it is a good pattern for this." Using the five-step recipe, what is missing?

Almost everything after step 1. It names the pattern but not its category (structural); it gives no problem in the scenario's terms (which external systems, and why their APIs differ); it maps no roles to classes (which class is the Target interface, which are the Adapters and Adaptees); and it names no GRASP justification (PV against changing external interfaces, Low Coupling, Indirection) or trade-off (one adapter per adaptee). Usage code, if asked, would show the client holding only the Target interface type.

Check yourselfIn a pattern diagram, TaxMasterAdapter is joined to «interface» ITaxCalculatorAdapter with a solid line and a hollow triangle. What is wrong, and what does the corrected arrow mean in Java?

Implementing an interface is realisation, drawn with a dashed line and hollow triangle. The solid line with a hollow triangle means generalisation (extends a class). The corrected arrow means class TaxMasterAdapter implements ITaxCalculatorAdapter.

In short
  • A pattern is a named problem/solution pair with advice and trade-offs; the name gives a shared vocabulary.
  • GoF's 23 patterns are creational, structural or behavioural. Simple Factory is taught but is not GoF.
  • Every GoF pattern is a Pure Fabrication; most use Indirection and/or Polymorphism to deliver Protected Variations.
  • Write about a pattern in five steps: name and category, problem in scenario terms, roles mapped to classes, GRASP justification plus trade-off, usage code.
6.2

Façade structural exam

Some parts of a system are big and messy: dozens of interdependent classes, a third-party library, or a part whose design hasn't even been decided yet. If every other class talks to it directly, they all become coupled to its insides, and any change ripples outwards. Façade solves this by putting one front door on the subsystem.

Intent (GoF)

Provide a unified, higher-level interface to a set of interfaces in a subsystem, so that the subsystem is easier to use.

Larman phrases the problem as a question: a common, unified interface to a disparate set of implementations or interfaces (such as within a subsystem) is required; there may be undesirable coupling to many things in the subsystem, or its implementation may change. What to do? His solution is to define a single point of contact to the subsystem: a façade object that wraps it, presents one unified interface, and is responsible for collaborating with the subsystem's components. Everything else in the subsystem is private.

The problem, and the fix

The lecture's ATM example shows the problem plainly. To withdraw cash, the ATM has to check the account number, check the security code, check the funds, update the account and record a transaction, each in a different class.

ATMAccountNumberCheckSecurityCodeCheckFundsCheckAccountTransactionATM must know all fiveclasses, their APIs andthe order to call them.Change one: ATM breaks.5 dependencies from one client
Without a façade, the ATM is coupled to five classes. It must know every class's API and the right order to call them. Any change inside the bank's code, even renaming a method in FundsCheck, can break the ATM.
ATMBankAccountFacade-accountNumber-securityCode+withdrawCash(amount)+depositCash(amount)bank subsystemAccountNumberCheckSecurityCodeCheckFundsCheckAccountTransactionusesone dependency from the client
With BankAccountFacade, the ATM has one dependency. The façade is created with (accountNumber, securityCode) and offers just withdrawCash(amount) and depositCash(amount). Internally it coordinates AccountNumberCheck, SecurityCodeCheck, FundsCheck, Account and Transaction; the ATM no longer knows they exist.

Structure and participants

ClientAClientBFaçade+operationA()+operationB()SubsystemClassAClassBClassCClassDClassEclients see one class,the subsystem stays private
The generic shape. Arrows go one way only: clients → Façade → subsystem. Nothing in the subsystem points back at the façade, and the clients never reach past it.

There are three participants:

  • the Façade, whose interface is tailored to what external clients need. It may deliberately not expose everything the subsystem can do;
  • the subsystem classes, which do the real work and don't know the façade exists;
  • the clients, which talk only to the façade.

Notice there is no interface in the generic structure. Unlike Adapter or Decorator, Façade doesn't rely on polymorphism; it is pure Indirection. That is a useful clue when you are deciding between patterns.

Exam cues for Façade

In exam wording, the symptoms are "complex or proprietary subsystems" that "a new system uses only in limited circumstances", or that need "a limited but straightforward interface". Other cues are "many interdependent classes the client shouldn't have to know", "low impact on existing code", "implementation not yet decided or may change", and "structure a subsystem into layers".

Course example 1: pluggable business rules in the NextGen POS

This is Larman's main example (26.9) and the lecture's. The customers want rules that can invalidate an action. For example:

  • a gift-card sale may contain only one item and must give no cash change;
  • a charity sale may only be rung up by a manager as cashier, and no item may cost over $250.

The architect wants these rules to have low impact on existing components, and is not yet sure how the rules will be implemented: as Strategy objects, with a free rule interpreter, or with a commercial one. A façade hides that choice completely. Behind it, the rule engine could be hundreds of classes, or not even object-oriented, and the domain objects would never know.

DomainSale+makeLineItem(desc, qty)POSRuleEngine+ POSRuleEngineFacade1-instance: POSRuleEngineFacade-rules: List<IRule>+getInstance(): POSRuleEngineFacade+isInvalid(sli: SalesLineItem, s: Sale): boolean+isInvalid(p: Payment, s: Sale): booleanuses«interface»- IRule+invalidates(sli, s): boolean1*rules- Rule1- Rule2+ = visible outside the package- = private to the package:only the façade can be seenfrom outside
Larman draws this as a package diagram. The visibility markers on the class names do the work: + POSRuleEngineFacade is public, while - IRule, - Rule1 and - Rule2 are private to the package, so only the façade can be seen from outside. The "1" and underlined members show that the façade is also a Singleton (6.8), which is usual for façades.

In code, the façade is public and the rule interface is package-private. The domain class Sale gets a one-line hook: before adding a line item, it asks the façade whether the item is invalid.

// package posruleengine
public class POSRuleEngineFacade {
    private static POSRuleEngineFacade instance;              // façades are usually Singletons
    private final List<IRule> rules = new ArrayList<>();      // hidden subsystem parts

    private POSRuleEngineFacade() { /* load rules: Strategy objects, a rule interpreter, ... */ }

    public static synchronized POSRuleEngineFacade getInstance() {
        if (instance == null) instance = new POSRuleEngineFacade();
        return instance;
    }
    public boolean isInvalid(SalesLineItem sli, Sale sale) {
        for (IRule r : rules) if (r.invalidates(sli, sale)) return true;
        return false;
    }
}
interface IRule { boolean invalidates(SalesLineItem sli, Sale sale); }   // package-private

// client: the one-line hook into the domain (Larman / lecture code)
public class Sale {
    public void makeLineItem(ProductDescription desc, int quantity) {
        SalesLineItem sli = new SalesLineItem(desc, quantity);
        if (POSRuleEngineFacade.getInstance().isInvalid(sli, this)) return;   // call to the Façade
        lineItems.add(sli);
    }
}

Step through the same code as a sequence diagram to see the collaboration at run time.

One call through the façade
:Sale:POSRuleEngineFacade1r : IRulelineItems : ListmakeLineItem(desc, qty)create(desc, qty)sli : SalesLineItemisInvalid(sli, this)loop[for each r in rules]invalidates(sli, sale)falseopt[not invalid]add(sli)
  1. The participants. Sale is the client. The façade, the rules and the line-item list are faded until they take part.
  2. The system operation reaches :Sale as makeLineItem(desc, qty).
  3. Sale creates the new sli : SalesLineItem. The create arrow points at the new object's box, drawn at the height where it is created.
  4. Sale asks the façade isInvalid(sli, this). The "1" on the façade's box means it was reached through Singleton, so getInstance() isn't drawn. This is the only message that leaves the domain.
  5. Inside the façade, hidden from Sale, a loop asks every rule invalidates(sli, sale). Today the rules are objects behind IRule; tomorrow they could be a commercial engine, and Sale would not change.
  6. The façade returns false: no rule objects to the item.
  7. So the opt fragment runs and Sale adds sli to its lineItems. Had the answer been true, makeLineItem would simply have returned.

Course example 2: the ATM

The ATM example from the tabs above is the lecture's. BankAccountFacade(accountNumber, securityCode) offers withdrawCash(amount) and depositCash(amount), and internally coordinates the five classes AccountNumberCheck, SecurityCodeCheck, FundsCheck, Account and Transaction. Without the façade, the ATM would be coupled to all five.

Course example 3: Monopoly LuckCards (workshop 7)

When a player lands on Go To Jail, they now draw from a deck of 5 cards: 1 × JailExemptionCard (stay where you are), 2 × GoToJailCard (move to Jail) and 2 × PayJailFeeCard (pay $500, or go to Jail if you can't afford it). The requirement was that GoToJailSquare should change by roughly one statement.

GoToJailSquare+landedOn(p: Player)CardDeckFacade1-instance: CardDeckFacade-rand: Random-jailCardDeck: ArrayList<JailCard>+getInstance(): CardDeckFacade+drawJailCard(): JailCard-initialCardDeck()usesCardJailCard«use»JailExemptionCard×1: stay whereyou areGoToJailCard×2: move toJailPayJailFeeCard×2: pay $500, or go toJail if you can't afford it
The workshop solution, CardDeckFacade. It is a Singleton that creates the cards (initialCardDeck()) and draws from them (drawJailCard()). The card classes sit behind a «use» dependency on the Card package, and each card applies its own effect polymorphically. (JailCard is the cards' common supertype; it is drawn here as an abstract class.)

The "one statement" in GoToJailSquare's landedOn becomes a call such as CardDeckFacade.getInstance().drawJailCard(), followed by letting the drawn card apply its effect. Everything about the deck, the random draw and the card mix stays behind the façade.

Why it works: GRASP

GRASP behind Façade

Façade uses Indirection to get Low Coupling, because external objects couple to a single point. It gives Protected Variations against changes in the subsystem's implementation, and it supports separation of concerns: rule handling, for example, moves out of the domain objects. Façades are usually accessed through a Singleton.

Façade versus Controller

The workshop 7 slides warn against confusing Façade with the GRASP Controller of Part IV, partly because Larman himself uses the phrase "façade controller".

GRASP ControllerGoF Façade
What it isThe first object beyond the UI layer that receives and coordinates a system operationA simpler interface to a complex subsystem
It followsThe business workflow of the use caseWhat the client needs from the subsystem
ExampleRegister handling enterItemPOSRuleEngineFacade, BankAccountFacade

Larman's "façade controller" (for example a Register that represents the whole system) is a Controller that happens to act as a front for the domain layer. Don't let the name trick you into calling it a GoF Façade.

Consequences and pitfalls

Benefits
  • Clients couple to one class instead of many.
  • The subsystem can change, or even be replaced, without touching clients.
  • Lets you build a system in layers, each fronted by a façade.
Pitfalls
  • The façade can grow into a bloated, low-cohesion "god object". If it does, split it per concern.
  • It should delegate, not contain business logic itself.
  • It doesn't stop clients reaching subsystem classes unless those classes are non-public.
  • It can hide advanced features some clients need. That is acceptable: a façade may expose only what is needed.
Check yourselfA new hotel booking app must use a legacy reservation system of 40 interdependent classes, but only to check availability and book a room. The legacy system is due to be rewritten next year. Which pattern, and why?

Façade (structural). The cues are a complex subsystem, used only in limited circumstances, and an implementation that will change. Create a ReservationFacade with just checkAvailability(...) and bookRoom(...); the app talks only to it. Indirection gives Low Coupling (one dependency instead of 40), and PV: when the legacy system is rewritten, only the façade's insides change. Trade-off: the façade must not swell into a god object as more features are requested.

Check yourselfA student's RuleEngineFacade.isInvalid() contains 200 lines of if statements that check gift-card and charity rules directly. They argue "it's a façade, it hides the rules". What is wrong?

A façade should delegate to the subsystem, not contain the business logic. Putting every rule inside it makes it a bloated, low-cohesion god object, and you lose the point of the design: the rules can no longer be swapped for Strategy objects or a rule interpreter without editing the façade. The rules belong in subsystem classes (such as IRule implementations) that the façade calls.

Check yourselfTrue or false: once you add a façade, clients can no longer use the subsystem classes directly.

False. A façade offers a convenient front door, but it doesn't lock the side doors. Clients can still reach subsystem classes unless those classes are made non-public, which is exactly why Larman's package diagram marks IRule, Rule1 and Rule2 as private (-) to the package.

In short
  • Façade puts one simplified front door on a complex subsystem; clients couple only to it.
  • Course examples: POSRuleEngineFacade (pluggable rules), BankAccountFacade (ATM), CardDeckFacade (Monopoly). Façades are usually Singletons.
  • GRASP: Indirection → Low Coupling, plus PV against subsystem changes. It is not the same as a GRASP Controller.
  • Keep it thin: delegate, don't hold business logic, and split it if it bloats.
6.3

Decorator structural exam

A noodle shop sells a base soup, and customers add any number of extras: prawns, egg, tofu, chilli, even two eggs. Every extra changes the same few outputs: the price, the ingredient list, the allergens. How do you model "a base thing plus any combination of add-ons, chosen while the program runs" without writing a class for every combination? That is Decorator's problem.

Intent (GoF)

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

The slides pose the problem as: how do we dynamically add behaviour or state to individual objects at run time, without changing the interface presented to the client? Inheritance doesn't fit, for two reasons. It is static, fixed when the code is compiled, and it applies to the whole class, whereas we want to change one instance, in any combination.

The problem, and the fix

NoodleSoupNoodleSoupWithPrawnsNoodleSoupWithEggNoodleSoupWithTofuNoodleSoupWithPrawnsAndEggNoodleSoupWithPrawnsAndTofuNoodleSoupWithEggAndTofuNoodleSoupWithPrawnsEggAndTofu3 extras → 7 subclassesup to 2ⁿ classes in all for n extras:4 extras → 16, 10 extras → 1024still not enough"two eggs" needs yet another classfixed at compile timea customer can't add prawns to a soupobject that already exists
Subclassing every combination explodes. With just three extras there are already seven subclasses, and the count roughly doubles with each new extra. Worse, a soup object can never gain an extra after it is created, because its class is fixed.
Client«interface»Component+operation()ConcreteComponent+operation()Decorator#component: Component+operation()1componentConcreteDecoratorA+operation()-addBehaviour()ConcreteDecoratorB+operation()-addBehaviour()operation() {component.operation();addBehaviour();}
Decorator: one class per extra, stacked at run time. The key is the Decorator: it both is a Component (dashed realisation, so the client can't tell it apart from the core) and has exactly one Component (the aggregation with multiplicity 1). Because the thing it holds may itself be a decorator, layers can nest without limit.

The slides' solution: encapsulate the original concrete object inside an abstract wrapper interface, and let the decorators that hold the extra behaviours also inherit from that interface. The interface then uses recursive composition to allow an unlimited number of decorator "layers" around each core object.

Participants

  • Component: an interface or abstract class. As workshop 7 puts it, "we can use either an interface OR an abstract class … at the top".
  • ConcreteComponent: the core object being decorated (the plain soup).
  • Decorator: abstract. It implements Component and also holds one Component, the wrapped object. By default it simply forwards every call to it.
  • ConcreteDecorator: overrides operations, calling the wrapped object and adding its own behaviour (addBehaviour()) either before or after that call.
The notation detail markers look for

The link from Decorator back to Component, with multiplicity 1, is the recursive composition. Without it, you have drawn plain inheritance, not Decorator. The lecture draws it as aggregation (hollow diamond) and workshop 7 uses a filled diamond; both are accepted.

Watching it work: a laksa, layer by layer

The past-exam noodle soup scenario appeared in both semesters' MCQs (S1 Q1.2 and S2 Q1.4). Here is one order being built, then priced.

Wrapping a soup in decorators
:Prawns+4.00:Egg+1.50:Egg+1.50:NoodleSouplaksa · rice · 12.00order.getPrice()12.0013.5015.0019.00Layers, innermost first:NoodleSoupbase12.00:Egg+ 1.5013.50:Egg+ 1.5015.00:Prawns+ 4.0019.00Prawns also adds "prawns" to the ingredients,"crustacean" to the allergens and 30 s reheat.getPrice() = 12.0 + 1.5 + 1.5 + 4.0 = 19.00new NoodleSoup(12.0, "laksa", "rice")new Egg(new NoodleSoup(12.0, "laksa", "rice"))new Egg(new Egg(new NoodleSoup(12.0, "laksa", "rice")))Soup order = new Prawns(new Egg(new Egg(new NoodleSoup(12.0, "laksa", "rice"))));double price = order.getPrice(); // 19.0
  1. Start with the core, a NoodleSoup: laksa with rice noodles at $12.00. On its own it is already a complete Soup.
  2. Wrap it in an Egg decorator. The Egg is a Soup and holds the NoodleSoup as its inner. Total so far: $13.50.
  3. Wrap the result in another Egg. No new class is needed for "double egg": the same class is simply used twice. $15.00.
  4. Wrap it all in Prawns, which adds $4.00, plus the ingredient "prawns", the allergen "crustacean" and 30 seconds of reheating. The client holds only the outermost object, typed as Soup.
  5. Now the client calls order.getPrice(). Each layer forwards the call inward to its inner, the core answers 12.00, and on the way out each layer adds its own amount: 13.50, 15.00, 19.00.

The code

«interface»Soup+getPrice(): double+getIngredients(): List<String>+getAllergens(): Set<String>+getReheatSeconds(): intNoodleSoup-basePrice: double-soupType: String-noodleType: String+getPrice(): double+getIngredients(): List<String>+getAllergens(): Set<String>+getReheatSeconds(): intSoupDecorator#inner: Soup+getPrice(): double+getIngredients(): List<String>+getAllergens(): Set<String>+getReheatSeconds(): int1innerPrawns+getPrice(): double+getIngredients(): List<String>+getAllergens(): Set<String>+getReheatSeconds(): intEggTofu, Chilli … arewritten the same way
The noodle soup classes. Soup is the Component, NoodleSoup the ConcreteComponent, SoupDecorator the abstract Decorator holding inner, and Prawns, Egg and so on are ConcreteDecorators.
public interface Soup {                                   // Component
    double getPrice();
    List<String> getIngredients();
    Set<String> getAllergens();
    int getReheatSeconds();
}

public class NoodleSoup implements Soup {                 // ConcreteComponent
    private final double basePrice; private final String soupType, noodleType;
    public NoodleSoup(double basePrice, String soupType, String noodleType) {
        this.basePrice = basePrice; this.soupType = soupType; this.noodleType = noodleType;
    }
    public double getPrice()             { return basePrice; }
    public List<String> getIngredients() { return new ArrayList<>(List.of(soupType, noodleType)); }
    public Set<String> getAllergens()    { return new HashSet<>(Set.of("gluten")); }
    public int getReheatSeconds()        { return 120; }
}

public abstract class SoupDecorator implements Soup {     // Decorator
    protected final Soup inner;                           // the wrapped component
    protected SoupDecorator(Soup inner) { this.inner = inner; }
    public double getPrice()             { return inner.getPrice(); }        // default: forward
    public List<String> getIngredients() { return inner.getIngredients(); }
    public Set<String> getAllergens()    { return inner.getAllergens(); }
    public int getReheatSeconds()        { return inner.getReheatSeconds(); }
}

public class Prawns extends SoupDecorator {               // ConcreteDecorator
    public Prawns(Soup inner) { super(inner); }
    @Override public double getPrice() { return inner.getPrice() + 4.00; }
    @Override public List<String> getIngredients() { List<String> l = inner.getIngredients(); l.add("prawns"); return l; }
    @Override public Set<String> getAllergens() { Set<String> s = inner.getAllergens(); s.add("crustacean"); return s; }
    @Override public int getReheatSeconds() { return inner.getReheatSeconds() + 30; }
}
// Egg, Tofu, Chilli ... are written the same way.

// Client: any combination, chosen at run time, through the same interface
Soup order = new Prawns(new Egg(new Egg(new NoodleSoup(12.0, "laksa", "rice"))));
double price = order.getPrice();          // 12.0 + 1.5 + 1.5 + 4.0
Set<String> allergens = order.getAllergens();

Three things to notice. Each decorator's constructor takes a Soup, which is what lets layers nest. The abstract decorator's default forwarding means a concrete decorator only overrides what it changes. And the client line never mentions a decorator type on the left-hand side: it is just a Soup.

Course example 1: shapes (lecture)

The component is Shape with draw(), and Rectangle implements it. The abstract ShapeDecorator implements Shape holds protected Shape decoratedShape, and its draw() forwards. RedShapeDecorator.draw() calls decoratedShape.draw() and then setRedBorder(decoratedShape). The sequence diagram below shows a rectangle with a blue fill, wrapped by a red border.

:Client:RedShapeDecorator:BlueShapeDecorator:Rectangledraw()draw()draw()setBlueFill()setRedBorder()
Dynamics: the call goes all the way in before any decoration happens. Each decorator first forwards draw() to the object it wraps, then adds its own decoration on the way back. So the rectangle is drawn first, then filled blue, then given its red border.

Course example 2: Monopoly houses and gardens (workshop 7, part 2)

Here the abstract Square with landedOn(Player) is the Component, and RegularSquare is the ConcreteComponent. The abstract SquareDecorator extends Square, holds wrapped: Square and owner: Player, and adds collectIncome(). House (+$20 to the owner) and Garden (+$5 × visits, with INCOME_PER_VISIT and n_visits) are the concrete decorators.

Square+landedOn(p: Player)RegularSquareSquareDecorator#wrapped: Square#owner: Player+landedOn(p: Player)+collectIncome()1wrappedHouse+collectIncome()Garden-INCOME_PER_VISIT-n_visits+collectIncome()owner gets +$20owner gets +$5 × visitsOne board slot over time:RegularSquarea player lands on it:new House(square, player):House:RegularSquarethe owner lands again:wrapped again, in a Garden:Garden:House:RegularSquareTwo houses and three gardens?Just add more layers.
Decorating squares on the board. When a player lands on an empty regular square, that square is replaced on the board by new House(square, player); when the owner lands there again, it is wrapped again in a Garden. The workshop's partial solution notes that a rule change, such as two houses and three gardens, needs only more layers, not new classes.

Why it works: GRASP

GRASP behind Decorator

Decorator relies on Polymorphism (decorators are substitutable for the component) and Indirection. It gives Protected Variations and follows the open–closed principle, because new features need no edits to existing classes. It also gives High Cohesion (one feature per decorator) and Low Coupling (the client sees only Component).

Consequences and pitfalls

Benefits
  • More flexible than static inheritance: with n optional features you write n classes instead of up to 2n subclasses.
  • You pay only for the features you use.
Costs
  • Identity. A decorated object is a different object from the core, so ==, equals and instanceof RegularSquare all fail on the wrapper, and the core's extra methods can't be reached through it.
  • Ordering. If decorators don't commute, order matters (see below). Fix the order in a Factory or Builder.
  • Many small look-alike objects make debugging harder, and removing a layer from the middle is awkward.
  • Every Component operation must be forwarded. That is why the abstract Decorator supplies default forwarding, and why the Component interface should be kept small.

Here is the ordering problem with a $10 pizza, a "10% discount" decorator and a "+$2 topping" decorator. The same two decorators, stacked in different orders, give different prices.

:Topping+$2:Discount−10%:Pizza $10.0010.00 × 0.9 = 9.009.00 + 2.00= $11.00
Discount first, then topping: $11.00.
:Discount−10%:Topping+$2:Pizza $10.0010.00 + 2.00 = 12.0012.00 × 0.9= $10.80
Topping first, then discount: $10.80.
Exam cues for Decorator

The typical scenario says "choose a base item, then add any number of extras or options from a long list": noodle soup ingredients, car customisations, pizza toppings, coffee add-ons, borders and fills on a shape, a house and garden on a square. Each add-on changes the same outputs (price, description, ingredients, allergens, rent), the "base behaviour stays the same", and the aim is to "avoid a subclass for every combination".

Check yourselfA car configurator lets buyers start from a base model and add any of 30 options (sunroof, tow bar, premium audio…), each changing the price and the feature list. Which pattern, and how many classes do the options need?

Decorator. "Base item plus any number of extras, each changing the same outputs" is its signature. Car is the Component interface (getPrice(), getFeatures()), BaseModel the ConcreteComponent, an abstract CarOptionDecorator holds one Car, and each option is one ConcreteDecorator. That is 30 option classes (plus the abstract decorator), instead of up to 230 subclasses.

Check yourselfUsing the soup code, what does new Egg(new Prawns(new NoodleSoup(10.0, "pho", "rice"))).getPrice() return, and does the order of Egg and Prawns matter here?

10.0 + 4.0 (Prawns) + 1.5 (Egg) = 15.5. Here the order doesn't matter, because every decorator only adds to the price, and addition commutes. It would matter if one decorator multiplied, like a percentage discount.

Check yourselfSpot the error: a student's diagram has Component, ConcreteComponent, and an abstract Decorator that realises Component, with ConcreteDecorators below it. There is no other line from Decorator. What's missing, and what goes wrong in code?

The aggregation from Decorator to Component with multiplicity 1 is missing. Without it the decorator holds nothing, so it has nothing to forward to and nothing to wrap: it is just ordinary subclassing. In code, the decorator would have no protected Component component field and no constructor taking a Component, so new Prawns(new NoodleSoup(...)) couldn't be written.

Check yourselfIn the Monopoly design, a test does if (board.getSquare(5) instanceof RegularSquare) after a house has been built on square 5. Why does it fail?

Square 5 on the board has been replaced by a House object that wraps the RegularSquare. The House is a different object, of class House, so instanceof RegularSquare is false. This is Decorator's identity cost: the wrapper is substitutable as a Square, but it is not the core object.

In short
  • Decorator adds responsibilities to one object at run time by wrapping it in objects with the same interface.
  • The Decorator both is a Component and has a Component (multiplicity 1): recursive composition, so layers stack without limit.
  • n features → n classes, not 2n. Costs: identity, ordering, many small objects, forwarding every operation.
  • Cue: "base item plus any number of extras that change the same outputs".
6.4

Builder creational

Some objects are hard to make. They have many parts or optional fields, they must be assembled in the right order, and building them takes domain knowledge the code that uses them shouldn't need. If that construction code lives in the client, the client becomes cluttered and has to change whenever the product does. Builder moves the whole job of construction into its own object.

Intent (GoF)

Separate the construction of a complex object from its representation, so that the same construction process can create different representations.

The slides pose the problem as two questions. How can a class (the same construction process) create different representations of a complex object? And how can a class that includes creating a complex object be simplified? Their solution: encapsulate creating and assembling the parts of a complex object in a separate Builder object. A class delegates object creation to a Builder instead of creating the objects directly.

Symptoms to recognise
  • a "complex object built step by step", with "many parts or optional fields";
  • a "monstrous constructor with lots of parameters": the telescoping constructor;
  • "creation code scattered over the client";
  • "same steps, different products": a stone house or a wooden one, apple juice or orange juice;
  • "construction needs complex domain knowledge the client doesn't want to know".

The problem, and the fix

RegularSquare+landedOn(p: Player)House-numRooms: int-amountGenerated: float-labourCost: float-houseType: String+setNumRooms(n: int)+setAmountGenerated(a: float)+getAmountGenerated(): float«create»if (netWorth <= 100) {// lay a single-pen foundation, rooms, roof…} else if (netWorth <= 300) {// saddlebag: house.setNumRooms(2); …} else {// dogtrot …}// work out the rent per visitor here toothe client holds all theconstruction knowledge
The client knows how every kind of house is built. RegularSquare has to decide the house type, lay each part in the right order and compute the rent. Add a fourth house type and RegularSquare must change.

The other face of the same problem is the telescoping constructor: one constructor with a long list of parameters, many of them optional, where nobody can remember which true means what.

Pizza p = new Pizza(30, true, false, true, false, false, true);   // which flag is ham?
ClientDirector-builder: Builder+construct()Builder+buildPartA()+buildPartB()+getResult(): Product1builderConcreteBuilder1+buildPartA()+buildPartB()+getResult(): ProductConcreteBuilder2+buildPartA()+buildPartB()+getResult(): ProductProduct«create»construct() {builder.buildPartA();builder.buildPartB(); }
GoF Builder. The Director knows the order of the steps; each ConcreteBuilder knows how to do each step for one representation, and hands out the finished Product through getResult(). Swap the builder and the same construct() makes a different product.

Participants

  • Builder: the abstract interface for building the parts.
  • ConcreteBuilder: implements the steps, keeps the product being built, and returns it with getResult().
  • Director: calls the steps in a fixed order.
  • Product: what comes out.

Course example 1: Monopoly houses (workshop 7, part 3)

In this workshop, houses are built with the provided regularHouseBuilder.jar API, and the house type depends on the player's net worth: $50–100 builds a single-pen house, $101–300 a saddlebag, and $301 and above a dogtrot.

RegularSquareHouseManager-builder: HouseBuilder+HouseManager(netWorth: double)+construct(): HouseHouseBuilder#house: House+setFoundation()+setRooms()+setRoof()+setGeneratedAmount()+buildHouse(): House1builderHouse-numRooms: int-amountGenerated: float-labourCost: float-houseType: String+getAmountGenerated(): floathouse1SinglePenHousenet worth $50–100SaddleBagHousenet worth $101–300DogTrotHousenet worth $301 and above
Mapping the roles: HouseManager is the Director, HouseBuilder is the Builder, the three house subclasses are ConcreteBuilders, and House is the Product. buildHouse() plays the part of GoF's getResult().
public abstract class HouseBuilder {                   // Builder
    protected House house = new House();
    public abstract void setFoundation();
    public abstract void setRooms();
    public abstract void setRoof();
    public abstract void setGeneratedAmount();
    public House buildHouse() { return house; }         // GoF getResult()
}
public class SaddleBagHouse extends HouseBuilder {     // ConcreteBuilder: holds the domain knowledge
    public void setFoundation()      { /* saddlebag foundation */ }
    public void setRooms()           { house.setNumRooms(2); }
    public void setRoof()            { /* ... */ }
    public void setGeneratedAmount() { house.setAmountGenerated(/* computed rent per visitor */ 50.46f); }
}
public class HouseManager {                            // Director: fixes the construction order
    private final HouseBuilder builder;
    public HouseManager(double netWorth) {             // picks the representation
        builder = netWorth <= 100 ? new SinglePenHouse()
                : netWorth <= 300 ? new SaddleBagHouse() : new DogTrotHouse();
    }
    public House construct() {
        builder.setFoundation(); builder.setRooms(); builder.setRoof(); builder.setGeneratedAmount();
        return builder.buildHouse();
    }
}
// client (e.g. RegularSquare): knows nothing about how houses are built
float rent = new HouseManager(player.getNetWorth()).construct().getAmountGenerated();

In this code the Director chooses the builder itself from the net worth. The workshop's partial-solution sequence diagram does it slightly differently: the client creates SaddleBagHouse(netWorth) and passes it to HouseManager(builder), the manager calls the four steps, and the client then calls buildHouse(): House on the builder. Step through that version below.

Building a saddlebag house
:RegularSquarecreate(netWorth)b : SaddleBagHousecreateh : Housecreate(b)m : HouseManagerconstruct()setFoundation()setRooms()setNumRooms(2)setRoof()setGeneratedAmount()setAmountGenerated(…)buildHouse()hgetAmountGenerated()rent
  1. The client, a RegularSquare, needs a house for a player whose net worth is between $101 and $300.
  2. It creates the ConcreteBuilder for that representation, b : SaddleBagHouse.
  3. The builder's field initialiser creates the empty product, h : House. Nobody outside the builder holds it yet.
  4. The client creates the Director, m : HouseManager, handing it the builder.
  5. construct(): the Director runs the fixed recipe. First setFoundation().
  6. Then setRooms(). Only the saddlebag builder knows a saddlebag has two rooms, so it calls setNumRooms(2) on the house.
  7. Then setRoof() and setGeneratedAmount(), which stores the rent per visitor in the house. Same four steps for every house type; only the builder differs.
  8. Only now does the client ask for the product: buildHouse() returns the finished h. Handing it out only at the end means nobody uses a half-built house.
  9. The client uses the product: getAmountGenerated() gives the rent. The client never saw a single construction step.

Course example 2: the lecture's generic sequence

The lecture's generic version runs in three steps: (1) the client calls Director.getWidget("One"): Widget; (2) the Director creates ConcreteBuilderOne and calls buildWidget(): Widget; (3) the builder creates the Widget and calls its own buildPartA(), buildPartB() and buildPartC().

:Client:DirectorgetWidget("One")createb : ConcreteBuilderOnebuildWidget()createw : WidgetbuildPartA()buildPartB()buildPartC()ww : Widget
Here the build order lives inside the builder. buildWidget() calls the part-building steps on itself, so the Director only chooses which builder to use.

Course example 3: juice (lecture)

The sequence starts with BuilderClient → ShopKeeper.takeOrder(juiceType): Juice. ShopKeeper is the Director, and it aggregates the abstract builder JuiceMaker, which has setFruit(), setWater(), setSugar() and public final Juice makeJuice(). OrangeJuiceMaker and AppleJuiceMaker implement the steps. makeJuice() creates the juice, calls setJuiceType(), setWater(), setFruit() and setSugar(), and returns it. Because it is final, no subclass can change the recipe, which guarantees every juice is made the same way.

BuilderClientShopKeeper+takeOrder(juiceType): JuiceJuiceMaker+setFruit()+setWater()+setSugar()+makeJuice(): Juice {final}1OrangeJuiceMakerAppleJuiceMakerJuice«create»
The juice builder. makeJuice() is {final}: the order of steps is fixed in the abstract builder, and the subclasses only fill in the steps.
Who owns the order of the steps?

In the lecture examples the build order sits in a final method of the abstract builder, which makes it a Template Method (Part VII) inside the Builder. In GoF, the Director owns the order. Either is fine, as long as the same process yields different representations.

Why it works: GRASP

GRASP behind Builder

Director and Builder are Pure Fabrications: neither is a domain concept. The pattern gives High Cohesion, because construction knowledge is separated from use, and Low Coupling, because the client knows only the Director or the abstract Builder. It gives PV too, since a new representation is just a new ConcreteBuilder. Builder is what you reach for when GRASP Creator would load the creator with complex assembly logic.

Consequences and pitfalls

Benefits
  • The product's internal representation can vary.
  • Construction code is isolated in one place.
  • You get step-by-step control over construction.
Costs
  • More classes: one ConcreteBuilder per representation.
  • The product must not be used before it is finished, so hand it out only through getResult() or buildHouse().

You will also meet the fluent builder Java idiom, which solves the telescoping-constructor problem without a Director. It is a popular variant, not the GoF structure:

Pizza p = new Pizza.Builder(size).cheese().ham().build();
Check yourselfA reporting tool must produce the same report (title, summary table, chart, footer, in that order) as either a PDF or an HTML page, and more formats will follow. Which pattern, and which class plays each role?

Builder: "same construction process, different representations". An abstract ReportBuilder (Builder) declares buildTitle(), buildSummary(), buildChart(), buildFooter() and getResult(); PdfReportBuilder and HtmlReportBuilder are ConcreteBuilders; a ReportDirector calls the four steps in order; the PDF document or HTML page is the Product. A new format is one new ConcreteBuilder (PV).

Check yourselfIn GoF Builder, who decides the order of the construction steps? Who decides it in the lecture's juice example?

In GoF, the Director. In the juice example, the abstract builder's final makeJuice() method fixes the order, a Template Method inside the Builder; the ShopKeeper (Director) just picks which JuiceMaker to use and asks it for the juice.

Check yourselfWhy does HouseBuilder hand the house out only through buildHouse(), rather than letting clients read house directly while construction is going on?

Because the product must not be used before it is finished. Halfway through, the house might have rooms but no rent amount, so getAmountGenerated() would give a wrong answer. Returning the product only from buildHouse() (GoF's getResult()), after the Director has run every step, makes sure clients only ever see a complete house.

In short
  • Builder moves step-by-step construction of a complex object out of the client, so the same process can make different representations.
  • Roles: Builder, ConcreteBuilder (knows how), Director (knows the order), Product (handed out at the end).
  • Course examples: HouseManager/HouseBuilder, the Widget sequence, ShopKeeper/JuiceMaker (order fixed in a final method).
  • Reach for it when Creator would overload a class with complex assembly logic, or for a telescoping constructor.
6.5

Adapter structural exam

Real systems talk to things they don't control: tax calculators, accounting packages, airline booking services, drones from different manufacturers. Several of them may do the same job through different APIs, and you can't change those APIs. Adapter lets your code treat them all the same way, through one interface that you define.

Intent (GoF)

Convert the interface of a class into another interface that clients expect. Adapter lets classes work together that otherwise couldn't, because their interfaces are incompatible.

Larman's problem: how to resolve incompatible interfaces, or provide a stable interface to similar components with different interfaces? His solution: convert the original interface of a component into another interface, through an intermediate adapter object. Note that "interface" here means the set of operations, not necessarily a Java interface.

Exam cues for Adapter

The classic symptom: "several external services, vendors, manufacturers, airlines or libraries do the same job through different APIs that cannot be changed". Related cues are "each driver is developed with a different interface", a need to "treat them uniformly", the warning that "more vendors will be added later", and "an existing class doesn't fit our interface".

The problem, and the fix

Tony's Pizza (the week 7 case study) delivers by drone, and its drones come from three manufacturers, each with its own software package. The packages differ in their payload types, in whether a location is a latitude/longitude or a street address, and in whether pizzas and drinks have separate compartments.

Client+deliverOrder(order)deliverOrder(order) {if (manufacturer == A) { … A's payloads, lat/long … }else if (manufacturer == B) { … street address … }else if (manufacturer == C) { … pizza + drink bays … }}// …and the same chain again in every other methodManufacturerA::DroneManufacturerB::DroneManufacturerC::Dronethree different APIs we cannot change
Without adapters, every method needs a chain of if (manufacturer == …) branches. One class becomes bloated and low in cohesion, and a fourth manufacturer means editing every chain. (The manufacturer package names here are placeholders.)
«interface»IDroneAdapter+deliverOrder(order: Order)+setRestaurant(r: Restaurant)ManufacturerADroneAdapter+deliverOrder(order: Order)+setRestaurant(r: Restaurant)-convertAddress(a: String): DroneLocationManufacturerBDroneAdapterManufacturerCDroneAdapterManufacturerA::Drone1adapteeManufacturerB::Drone1adapteeManufacturerC::Drone1adaptee
One adapter per manufacturer, all behind IDroneAdapter. Each adapter has an adaptee (aggregation, multiplicity 1) to its manufacturer's drone class, written Package::Class. It converts order items into that manufacturer's payloads and addresses into its location type.

The target interface IDroneAdapter has deliverOrder(order: Order) and setRestaurant(r: Restaurant). The whole Order is passed because it is the Information Expert on its items and delivery address. To convert addresses, each adapter uses a private helper convertAddress(String): DroneLocation that calls a maps service. It is private because its signature differs per manufacturer; separate location adapters would be the alternative.

Structure and participants

Client«interface»Target+request()Adapter+request()Adaptee+specificRequest()adaptee1request() {adaptee.specificRequest();// translate data both ways}
The object adapter. The Client knows only the Target. The Adapter implements Target and holds the Adaptee, translating each call (and its data) into the adaptee's own API.
  • Target: an interface that we define, such as ITaxCalculatorAdapter.
  • Adapter: implements the Target and holds a reference to the adaptee, translating both the calls and the data.
  • Adaptee: the existing external class or system.
  • Client: depends only on the Target.

Course example 1: Disney characters (lecture)

The lecture's toy example makes the idea concrete. A game wants every character to move(), but the characters come from an external library where a sloth must be woken and pushed to climb, Iron Man flies, and a trooper is controlled by a command string.

DisneyMadness+main(args: String[])«interface»IDisneyAdapter+move()SlothAdapter-theSloth: Sloth+move()Sloth+wake()+pushToClimb()«use»IronManAdapter+move()IronMan+fly()«use»TrooperAdapter+move()Trooper+control(cmd: String)«use»Sloth, IronMan and Trooper come from an external library we cannot change
Three adapters, one target. DisneyMadness sees only IDisneyAdapter.move(). Each adapter turns move() into whatever its character needs.
public interface IDisneyAdapter { void move(); }        // Target (our interface)

public class SlothAdapter implements IDisneyAdapter {   // Adapter
    private final Sloth theSloth;                       // Adaptee from an external library
    public SlothAdapter(String name) { theSloth = new Sloth(name); }
    public void move() { theSloth.wake(); theSloth.pushToClimb(); }   // translate one call into their API
}
// Client: no knowledge of how each character moves (lecture code)
IDisneyAdapter sloth = new SlothAdapter("Flash");   sloth.move();
IDisneyAdapter ironMan = new IronManAdapter("Tony"); ironMan.move();

Notice that one call to move() may become several calls on the adaptee. Translation is not always one-to-one.

Course example 2: NextGen POS external services (Larman 26.1)

The POS must work with several tax calculators (TaxMaster, GoodAsGoldTaxPro), accounting systems (SAP, GreatNorthern), credit authorisation services and inventory services, each with a fixed API. Larman defines one target interface per kind of service, and one adapter class per external system.

«interface»ITaxCalculatorAdapter+getTaxes(Sale): List<TaxLineItem>«interface»IAccountingAdapter+postReceivable(CreditPayment)+postSale(Sale)TaxMasterAdapterGoodAsGoldTaxProAdapterSAPAccountingAdapterGreatNorthernAccountingAdapter«interface»ICreditAuthorizationServiceAdapter+requestApproval(CreditPayment, TerminalID, MerchantID)«interface»IInventoryAdapter(operations not listed)one adapter classper external system;pattern name in theclass name
Larman's target interfaces. ITaxCalculatorAdapter.getTaxes(Sale): List<TaxLineItem>; IAccountingAdapter.postReceivable(CreditPayment) and postSale(Sale); ICreditAuthorizationServiceAdapter.requestApproval(CreditPayment, TerminalID, MerchantID); and IInventoryAdapter. Note the pattern name in every class name.
:Register:SAPAccountingAdapter«actor»:SAPSystempostSale(sale)SOAP over HTTP
At run time, :Register sends postSale(sale) to the :SAPAccountingAdapter, which talks "SOAP over HTTP" to the external «actor» :SAPSystem. Register never knows SOAP is involved.

A side note from Larman: while designing this, the class TaxLineItem appeared. It is a domain concept discovered during design, and can be added back to the Domain Model. Models evolve in both directions.

Course example 3: MiniExpedia (workshop 8)

MiniExpedia searches and books flights across Jetstar, Qantas and Virgin. The search target is ISearchAdapter.search(myFlights: ArrayList<IFlightAdapter>, numPassengers): ArrayList<IFlightAdapter>, implemented by JetstarSearchAdapter, QantasSearchAdapter and VirginSearchAdapter. Jetstar's search API has a stateful protocol: it must be called in exactly the right order, and calling it in the wrong state throws an exception. The adapter hides this sequence.

The adapter hides Jetstar's protocol
:Client:JetstarSearchAdapter:JetstarSearchsearch(myFlights, numPassengers)setNumPassengers(numPassengers)startInputFlights()loop[for each flight in myFlights]inputFlight(…)endInputFlights()search()loop[for each result i]getSearchResult(i)f : JetstarFlightcreate(f)fa : JetstarFlightAdapterresults
  1. The client knows only the target ISearchAdapter. Jetstar's own JetstarSearch class is faded: the client never sees it.
  2. The client makes one call: search(myFlights, numPassengers). Exactly the same call works for the Qantas and Virgin adapters.
  3. The adapter begins Jetstar's protocol: setNumPassengers, then startInputFlights.
  4. It feeds in the flights one at a time with inputFlight, in a loop.
  5. It closes the input with endInputFlights and only then runs search. Get this order wrong and Jetstar throws an exception, which is exactly the knowledge the adapter keeps out of the client.
  6. For each result it calls getSearchResult(i), gets back a Jetstar-specific JetstarFlight, and wraps it in a new JetstarFlightAdapter, so the data is adapted as well as the calls.
  7. The client receives results: a list of IFlightAdapter, indistinguishable from Qantas or Virgin results.
«interface»ISearchAdapter+search(myFlights, numPassengers): ArrayList<IFlightAdapter>JetstarSearchAdapterQantasSearchAdapterVirginSearchAdapterJetstarSearch1stateful protocol: wrong orderof calls throws an exception«interface»IFlightAdapter+getDeparture()+getDestination()+getAirline()+getAirfare()+getDepartureTime()+getArrivalTime()JetstarFlightAdapter+getOriginalObject(): JetstarFlightJetstarFlight1wraps
Adapting the data too. Each airline returns its own flight type, so IFlightAdapter declares getDeparture, getDestination, getAirline, getAirfare, getDepartureTime and getArrivalTime. JetstarFlightAdapter wraps a JetstarFlight and adds getOriginalObject(), so the booking adapter can unwrap it for JetstarBook.requestBooking(ArrayList<JetstarFlight>, …).

No adapter is needed for Passenger, because the IBookAdapter implementation creates the airline's own passenger objects itself. The client's search loop gets each adapter from a factory, which is where the next section begins:

searchAdapter = ServiceFactory.getInstance().getSearchAdapter(airlines[i]);
results.addAll(searchAdapter.search(myFlights, numPassengers));

Why it works: GRASP

GRASP behind Adapter

In Larman's words, Adapter is "a kind of Indirection and a Pure Fabrication, that uses Polymorphism". It gives Protected Variations against varying or changing external interfaces and supports Low Coupling. It also gives High Cohesion: each adapter handles exactly one external system, and connectivity concerns stay out of domain classes.

Variants: object adapter and class adapter

«interface»Target+request()Adapter+request()Adaptee+specificRequest()1has-a adaptee(composition)
Object adapter (used by the course and Larman): the adapter holds the adaptee by composition.
«interface»Target+request()Adaptee+specificRequest()Adapter+request()
Class adapter: the adapter inherits from the adaptee and implements the target. That needs multiple inheritance, so in Java it only works when the target is an interface.

Either way, an adapter may translate data in both directions: sending requests out, and turning replies back into our types (as JetstarFlightAdapter does). Exceptions should be translated to our level of abstraction too (Larman's "Convert Exceptions", ch. 36), so a SOAP fault doesn't leak into the domain layer.

Pitfalls, and the two questions Adapter raises

Pitfalls
  • You need one adapter per adaptee.
  • The translation can be substantial: protocol sequencing, unit and format conversion, error mapping.
  • An adapter should not add new business behaviour; it only translates.

Using adapters raises two follow-on questions, and two more patterns answer them. Who creates the adapters, and how is the right class chosen? That is Factory (6.6). How does everyone reach that factory? That is Singleton (6.8).

Check yourselfAn online shop must take payments through Stripe, PayPal and a local bank gateway, each with its own SDK, and the business expects to add more providers. Which pattern, and what is the Target?

Adapter (structural): several external services doing the same job through different, unchangeable APIs, with more to come. Define a Target interface we own, e.g. IPaymentAdapter.charge(Payment): Receipt, and one adapter per provider (StripeAdapter, PayPalAdapter, BankGatewayAdapter), each holding its SDK object as adaptee. The checkout code depends only on IPaymentAdapter: PV against provider changes, Low Coupling, High Cohesion (one provider per adapter). A Factory would choose which adapter to create.

Check yourselfSpot the error: in a student's Disney diagram, DisneyMadness has navigable associations to SlothAdapter, IronManAdapter and TrooperAdapter. What is wrong?

The client should depend only on the target interface IDisneyAdapter. Pointing at the concrete adapters couples DisneyMadness to each of them, so adding a fourth character means changing the client, which throws away the Protected Variations the pattern is for. Draw one association from DisneyMadness to IDisneyAdapter.

Check yourselfWhy is Tony's Pizza's convertAddress(String): DroneLocation a private method of each drone adapter rather than part of IDroneAdapter?

Because its signature differs per manufacturer: each one has its own location type. The target interface can only contain operations that every adapter offers with the same signature, and that the client needs. Address conversion is an internal translation step, so it is private; separate location adapters would be the alternative.

In short
  • Adapter converts an existing, unchangeable API into a Target interface we define; the client sees only the Target.
  • One adapter per external system, translating calls, data (both ways) and exceptions. Course: TaxMasterAdapter/SAPAccountingAdapter, Disney, MiniExpedia, Tony's drones.
  • GRASP: Indirection + Pure Fabrication + Polymorphism → PV against external interfaces, Low Coupling, High Cohesion.
  • It leads to two more patterns: a Factory creates the adapters and a Singleton makes the factory reachable.
6.6

Factory (Simple / Concrete Factory) creational, not GoF exam

Adapter left a loose end: somebody has to create the adapters, and somebody has to decide whether today's tax adapter is TaxMasterAdapter or GoodAsGoldTaxProAdapter. If a domain object does it, it gets tangled up in configuration and external connectivity. Factory gives that job to a dedicated object. Three designs share the word "factory"; this section covers the one the course uses most, and 6.7 covers the two GoF ones and compares all three.

Larman 26.4 · (Concrete / Simple) Factory

"Also called Simple Factory or Concrete Factory. This pattern is not a GoF design pattern, but extremely widespread. It is also a simplification of the GoF Abstract Factory pattern."

Its problem: who should be responsible for creating objects when there are special considerations, such as complex creation logic, or a desire to separate the creation responsibilities for better cohesion? Its solution: create a Pure Fabrication object called a Factory that handles the creation.

The problem, and the fix

The motivation comes straight from Adapter. Who creates the adapters, and how do we choose TaxMasterAdapter over GoodAsGoldTaxProAdapter? If a domain object such as Register did it, that would go beyond pure application logic into external connectivity. That breaks separation of concerns (an application of High Cohesion) and lowers Register's cohesion.

Register+enterItem(id, qty)+makePayment(cash)+endSale()TaxMasterAdapterGoodAsGoldTaxProAdapterSAPAccountingAdapter«create»if (config says TaxMaster) taxCalc = new TaxMasterAdapter();else taxCalc = new GoodAsGoldTaxProAdapter();accounting = new SAPAccountingAdapter();Register now does application logicAND external connectivity:lower cohesion
Register creating its own adapters. It is now coupled to every concrete adapter class and holds configuration logic that has nothing to do with selling things.
RegisterServicesFactory1-instance: ServicesFactory-accountingAdapter: IAccountingAdapter-inventoryAdapter: IInventoryAdapter-taxCalculatorAdapter: ITaxCalculatorAdapter+getInstance(): ServicesFactory+getAccountingAdapter(): IAccountingAdapter+getInventoryAdapter(): IInventoryAdapter+getTaxCalculatorAdapter(): ITaxCalculatorAdapter«interface»ITaxCalculatorAdapter+getTaxes(s: Sale): List<TaxLineItem>createsTaxMasterAdapterGoodAsGoldTaxProAdapter
Larman's ServicesFactory. Register asks the factory, and every get…Adapter() method returns an interface type, so the factory is free to return any implementation. The "1" in the corner marks it as a Singleton.
ClientFactory+createProduct(type): Product«interface»ProductreturnsProductAProductB«create»createProduct(type) {if (type == …) return new ProductA();…}
The generic shape. The client asks the Factory; the factory decides which concrete class to instantiate (from a parameter, configuration or reflection) and returns it typed as the Product interface.

What a factory buys you

Advantage 1

Cohesive creation

The responsibility for complex creation is separated into cohesive helper objects.
Advantage 2

Hidden logic

Potentially complex creation logic is hidden from the clients.
Advantage 3

Memory management

Performance-enhancing strategies become possible, such as object caching or recycling (for example, reusing a DB connection).
The key design point

Factory methods return interface types (IAccountingAdapter, not SAPAccountingAdapter), so the factory can return any implementation and the client never names a concrete class.

Data-driven and lazy: ServicesFactory in code

Larman's ServicesFactory adds two refinements. The choice of class is data-driven: it reads the class name from a system property (taxcalculator.class.name=TaxMasterAdapter) and instantiates it reflectively, so switching adapter needs no source change, which is PV. And it uses lazy creation: an adapter is created only when first asked for, and then cached.

public class ServicesFactory {                                   // Factory + Singleton
    private static ServicesFactory instance;
    private ITaxCalculatorAdapter taxCalculatorAdapter;

    private ServicesFactory() {}
    public static synchronized ServicesFactory getInstance() {
        if (instance == null) instance = new ServicesFactory();
        return instance;
    }
    public ITaxCalculatorAdapter getTaxCalculatorAdapter() {
        if (taxCalculatorAdapter == null) {                      // lazy creation
            String className = System.getProperty("taxcalculator.class.name");  // data-driven: PV
            try {
                taxCalculatorAdapter = (ITaxCalculatorAdapter)
                    Class.forName(className).getDeclaredConstructor().newInstance();
            } catch (ReflectiveOperationException e) { throw new IllegalStateException(e); }
        }
        return taxCalculatorAdapter;
    }
}
Lazy, data-driven creation
:Register:ServicesFactory1SystemgetTaxCalculatorAdapter()opt[taxCalculatorAdapter == null]getProperty(key)"TaxMasterAdapter"key = "taxcalculator.class.name"Class.forName(name)…newInstance():TaxMasterAdapteradaptercached in the fieldgetTaxCalculatorAdapter()same adapternot null: the opt is skipped,nothing is created
  1. Register needs a tax calculator. It reaches the factory through Singleton (the "1"), and knows nothing about which tax system is installed.
  2. It asks getTaxCalculatorAdapter(), expecting an ITaxCalculatorAdapter.
  3. The field is still null, so the opt fragment runs. The factory reads the system property taxcalculator.class.name and gets back the string "TaxMasterAdapter". The choice lives in configuration data, not in code.
  4. It creates that class by reflection (Class.forName(name)…newInstance()). Change the property to GoodAsGoldTaxProAdapter and a different class is built, with no recompiling: PV.
  5. The new adapter is cached in the field and returned, typed as the interface.
  6. The next call finds the field not null, skips the opt fragment and returns the same adapter: lazy creation, then caching.

The lecture's Disney version replaces reflection with a plain conditional:

// Disney version (lecture): a conditional instead of reflection
public IDisneyAdapter getDisneyAdapter(String character, String name) {
    if (character.equals("ironman")) return new IronManAdapter(name);
    if (character.equals("sloth"))   return new SlothAdapter(name);
    if (character.equals("trooper")) return new TrooperAdapter(name);
    return null;                     // the slides suggest an Enum instead of a String
}

Caching is a choice, not a rule. PricingStrategyFactory (Part VII) deliberately does not cache, because the pricing policy can change hourly, so it re-creates the strategy each time. And use a separate factory for each family of products, as with ServicesFactory and PricingStrategyFactory, because that keeps each factory cohesive.

The course's factories

FactorySystemCreates
ServicesFactoryNextGen POSthe external-service adapters (tax, accounting, inventory)
PricingStrategyFactoryNextGen POSpricing strategies (re-created each time, no caching)
DisneyFactorylecture Disney examplecharacter adapters, by a conditional
ServiceFactoryMiniExpediasearch (and booking) adapters per airline
DroneAdapterFactory.getAdapter(manufacturer: String): IDroneAdapterTony's Pizzadrone adapters
AssignmentStrategyFactory.getStrategy(): IAssignmentStrategyTony's Pizzadelivery-assignment strategies, after checking the time of day

All the shared ones are Singletons.

Why it works: GRASP

GRASP behind Factory

A factory is a Pure Fabrication. It gives High Cohesion through separation of concerns, and Protected Variations when the class to create is data-driven. Use it instead of GRASP Creator when creation is complex or configurable; when creation is simple, Creator is enough.

Pitfalls
  • A big if/else on strings has to be edited whenever a new type appears. Data-driven reflection or a map avoids that.
  • Reflection errors only surface at run time.
  • One factory for everything becomes a low-cohesion god class.
Check yourselfIn the NextGen POS, why shouldn't Register simply write taxCalc = new TaxMasterAdapter();? Name the GRASP principle involved.

Register is a domain object; choosing and constructing external-service adapters is external connectivity, not application logic. Doing it in Register breaks separation of concerns, an application of High Cohesion, and couples Register to a concrete adapter class, so switching tax systems means editing Register. A ServicesFactory (Pure Fabrication) takes the job and returns an ITaxCalculatorAdapter.

Check yourselfThe shop switches from TaxMaster to GoodAsGoldTaxPro. With Larman's ServicesFactory, which source files change?

None (assuming GoodAsGoldTaxProAdapter already exists). Only the system property taxcalculator.class.name changes; the factory reads it and instantiates the named class by reflection. That is the data-driven Protected Variations Larman highlights. The trade-off: a typo in the property only shows up as a run-time error.

Check yourselfServicesFactory caches its adapters, but PricingStrategyFactory re-creates its strategy on every call. Why the difference?

An external-service adapter stays the same for the life of the program, so creating it once and caching it saves work. The pricing policy can change hourly, so a cached strategy could be stale; PricingStrategyFactory re-creates it each time to pick up the current policy.

In short
  • (Simple/Concrete) Factory is a Pure Fabrication that does the creating; it is not GoF (Larman: a simplification of Abstract Factory).
  • Its methods return interface types; the concrete class can be chosen by a parameter, configuration or reflection.
  • ServicesFactory adds data-driven choice (PV) and lazy creation with caching; one factory per product family; shared factories are Singletons.
6.7

Factory Method and Abstract Factory creational, GoF

The two GoF patterns with "factory" in their name solve related but different problems. Factory Method lets a class leave one creation decision to its subclasses. Abstract Factory creates whole families of objects that must be used together. Knowing exactly how they differ from the Simple Factory above is the main exam value of this section.

Factory Method

Intent (GoF)

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method defers instantiation to subclasses.

In its structure, an abstract Creator declares createProduct(): Product, and may call it inside its own template-like operations. Each ConcreteCreator overrides it to return a ConcreteProduct. The workshop 8 slide describes it as "replace direct object construction calls with calls to a special factory method". Use it when you don't know the exact types in advance, to let users of a framework extend its internal components, or to save resources by reusing objects.

Creator+anOperation()#createProduct(): ProductConcreteCreator#createProduct(): Product«interface»ProductConcreteProduct«create»anOperation() { Product p = createProduct(); … }Dialog+render()#createButton(): ButtonWebDialog#createButton(): Button«interface»Button+render()HtmlButton«create»render() { Button ok = createButton(); ok.render(); }
Generic structure (left) and the Dialog example (right). render() is written once in Dialog and calls the factory method createButton(); WebDialog decides that the button is an HtmlButton. The creation decision lives in a subclass, not in a separate factory object.
public abstract class Dialog {                       // Creator
    public void render() { Button ok = createButton(); ok.render(); }
    protected abstract Button createButton();        // the factory method
}
public class WebDialog extends Dialog {              // ConcreteCreator
    protected Button createButton() { return new HtmlButton(); }
}

Abstract Factory (Larman 36.7)

Larman's problem: how to create families of related classes that implement a common interface? His solution: define a factory interface (the abstract factory), and define a concrete factory class for each family of things to create. Optionally, define a true abstract class that implements the factory interface and provides common services to the concrete factories that extend it.

His example is the JavaPOS device drivers. A store's cash drawer, coin dispenser and so on must all come from the same manufacturer's driver set. IJavaPOSDevicesFactory declares getNewCashDrawer(): jpos.CashDrawer, getNewCoinDispenser(): jpos.CoinDispenser and so on, and IBMJavaPOSDevicesFactory and NCRJavaPOSDevicesFactory each return their own manufacturer's driver family.

IBM familyNCR family«interface»IJavaPOSDevicesFactory+getNewCashDrawer(): jpos.CashDrawer+getNewCoinDispenser(): jpos.CoinDispenser…IBMJavaPOSDevicesFactoryNCRJavaPOSDevicesFactory«interface»jpos.CashDrawer«interface»jpos.CoinDispenserIBMCashDrawerNCRCashDrawerIBMCoinDispenserNCRCoinDispenser«create»«create»
One concrete factory per family. Pick the IBM factory and every device you get is an IBM driver; you can't accidentally mix an IBM drawer with an NCR dispenser. The concrete driver class names are illustrative; what matters is that each factory returns the jpos interface types.

There is also an abstract-class variant. The abstract JavaPOSDevicesFactory has a Singleton getInstance() that reads the system property jposfactory.classname and instantiates the matching subclass. Client code is then a single line, which gives PV over which family is used. java.awt.Toolkit works this way.

cashDrawer = JavaPOSDevicesFactory.getInstance().getNewCashDrawer();

Telling the three factories apart exam

The quickest way to tell them apart is the mechanism: one class decides, subclasses decide, or there is one concrete factory per family.

Simple / Concrete Factoryone class decidesFactory Methodsubclasses decideAbstract Factoryone factory per familyFactorycreate(type)ProductAProductBProductCCreatorCreatorAProductACreatorBProductBIDevicesFactoryIBMFactoryIBMDrawerIBMDispenserNCRFactoryNCRDrawerNCRDispenser
Who decides which class gets created? A single factory object; a subclass overriding a method; or whichever family's factory you hold.
Simple / Concrete FactoryFactory MethodAbstract Factory
GoF?No (Larman: "simplification of Abstract Factory")YesYes
MechanismOne Pure Fabrication class whose method(s) decide which concrete class to create (parameter, configuration, reflection)An overridable creation method in a class hierarchy; subclasses decideAn interface with several creation methods; one concrete factory per family
Typical cue"who creates the adapters/strategies?"; "complex creation logic""the framework must let subclasses choose the product""families of related objects that must be used together" (IBM drivers vs NCR drivers)
Naming trap

The slides say "Concrete Factory pattern is a part of Factory Method in GoF", and the workshop 8 slide is titled "Factory Method". Follow Larman instead: call the ServicesFactory kind Factory (Simple/Concrete Factory), a non-GoF simplification of Abstract Factory, and use "Factory Method" only for the subclass-decides form.

Check yourselfA GUI toolkit must create buttons, scroll bars and menus that all match, either in a Windows look or a macOS look; mixing looks is not allowed. Simple Factory, Factory Method or Abstract Factory?

Abstract Factory: "families of related objects that must be used together". A WidgetFactory interface declares createButton(), createScrollBar() and createMenu(); WindowsWidgetFactory and MacWidgetFactory each create one consistent family. Holding one factory guarantees the widgets match.

Check yourselfA classmate calls MiniExpedia's ServiceFactory.getSearchAdapter(airline) "the Factory Method pattern", because the workshop slide is titled that. How should you name it in the exam, and why?

Call it Factory (Simple/Concrete Factory), following Larman. A single factory object decides, from a parameter, which adapter to create; nothing is deferred to subclasses, so it is not GoF Factory Method. "Factory Method" is reserved for an overridable creation method whose subclasses choose the product, like Dialog.createButton().

In short
  • Factory Method: an abstract creation method in a class; subclasses decide the product (Dialog/WebDialog).
  • Abstract Factory: a factory interface with several creation methods; one concrete factory per family (IBM vs NCR JavaPOS drivers), often fronted by a Singleton reading a property.
  • Simple Factory = one class decides. Use Larman's names, not the slide title.
6.8

Singleton creational exam

Some things must exist exactly once: the one order log, the one configuration, the one factory that hands out adapters. Many objects scattered across the system need to reach that one object, and passing it along as a parameter through every method call would be tiresome. Singleton guarantees there is only one, and gives everyone a way to find it.

Intent (GoF)

Ensure a class has only one instance, and provide a global point of access to it.

Larman's problem: exactly one instance of a class is allowed (it is a "singleton"), and objects need a global and single point of access. His solution: define a static method of the class that returns the singleton.

Exam cues for Singleton

"There is only one X": the Premier, the board, the order log, the configuration, the simulated clock or time of day. An object that must be "available throughout the framework" or is "accessed from many places". The remark that "passing it around as a parameter would be inconvenient". Or the object is a shared factory, façade, logger or connection pool.

The problem, and the fix

Tony's Pizza (week 9) wants "a single log for all orders and deliveries". The class names on the left of these pictures are illustrative.

:OrderTakernew OrderLog()log1 : OrderLog:Kitchennew OrderLog()log2 : OrderLog:Dispatchernew OrderLog()log3 : OrderLogthree separate logs:each order's history isscattered, nothing seesthe whole picture.Passing one log aroundas a parameter insteadis clumsy.
Nothing stops anyone writing new OrderLog(). Each caller gets its own log, so no single object holds the whole history.
:OrderTaker:Kitchen:DispatchergetInstance():OrderLog1one shared log:"a single log for allorders and deliveries",reachable from anywhere
Everyone asks the class for its one instance. The constructor is private, so OrderLog.getInstance() is the only way in, and it always returns the same object.

Mechanics

ClientAClientBSingleton1-instance: Singleton-Singleton()+getInstance(): Singleton+serviceOperation()getInstance()1static field: the one instance2private: no outside new3public static access point4service: an instance method
Four parts make a Singleton. Underlined members are static; the "1" in the corner marks the class as a singleton.
  1. A private static field holds the sole instance.
  2. A private constructor, so there is no new from outside the class.
  3. A public static getInstance() that returns the instance.
  4. Service methods stay instance methods; only the access point is static.

Lazy versus eager initialisation exam

There are two ways to decide when the one instance is created.

// Lazy (Larman's preferred form): created on first use
public class ServicesFactory {
    private static ServicesFactory instance;
    private ServicesFactory() {}
    public static synchronized ServicesFactory getInstance() {   // synchronized: the creation step is
        if (instance == null) instance = new ServicesFactory();  // a critical section when multithreaded
        return instance;
    }
}
// Eager: created when the class is loaded
public class ServicesFactory {
    private static final ServicesFactory instance = new ServicesFactory();
    private ServicesFactory() {}
    public static ServicesFactory getInstance() { return instance; }
}
LazyEager
Createdon the first call to getInstance()when the class is loaded
Foravoids the creation work, and the cost of holding expensive resources, if the instance is never used; getInstance() can contain complex conditional creation logic (e.g. reading a property to choose a subclass). These are Larman's two reasons for preferring it.simpler; creation is thread-safe without locks, because the JVM initialises classes safely
Againstneeds concurrency control (synchronized) in multithreaded codethe instance is always created, used or not

Why does lazy initialisation need synchronized? Step through what can happen without it.

Two threads, one lazy Singleton
Thread AThread Bstatic field instancenullif (instance == null)→ trueif (instance == null)→ true: A hasn't assigned yetinstance = new …()creates object #1instance = new …()creates object #2→ object #1→ object #2A holds #1, B holds #2:TWO instancespublic static synchronized ServicesFactory getInstance()The check-then-create step becomes a critical section: B waits at the lock until A returns, then finds instance != null.
  1. Two threads call getInstance() at almost the same moment, and getInstance() is not synchronized. The static field instance is still null.
  2. Thread A checks instance == null: true, so it heads for the new.
  3. Before A gets there, the scheduler switches to Thread B. B checks too, and also sees true, because A hasn't assigned anything yet.
  4. A creates object #1 and stores it in the field.
  5. B, which already passed the check, creates object #2 and overwrites the field. A is using #1, B is using #2: two instances, and the guarantee is broken.
  6. The fix: make getInstance() synchronized. The check-then-create step becomes a critical section, so B waits until A has finished, then sees a non-null field and gets object #1.

Beyond the textbook, common Java idioms are the initialisation-on-demand holder (lazy, thread-safe, no locking), the enum singleton (also safe against serialisation and reflection), and double-checked locking, which needs a volatile field. Whichever you use, remember that thread-safe creation does not make the singleton's state thread-safe: a mutable counter inside it still needs synchronized or an AtomicInteger.

Why not just make every method static?

A class with only static methods also has "one copy". Larman gives three reasons to prefer a real instance:

  1. Polymorphism. Instance methods can be overridden in subclasses; static methods are not polymorphic. (This is what lets JavaPOSDevicesFactory.getInstance() return an IBM or NCR subclass.)
  2. Remoting. Remote mechanisms such as Java RMI only remote-enable instance methods.
  3. Flexibility. A class is not a singleton in every application, and designs often discover later that they need several instances (a "multi-ton"). Instance-side code keeps that option open.

Singleton in UML

In the class box, draw a "1" in the top-right corner and underline the static instance and getInstance() (see the notation figure in 6.1). In a sequence diagram, a lifeline box marked "1", such as 1 :ServicesFactory, means visibility came through Singleton, and the getInstance() message is then implicit and not drawn (Larman Fig. 26.7). In code this is:

aa = ServicesFactory.getInstance().getAccountingAdapter();

Course singletons

NextGen POS

Factories and façade

ServicesFactory, PricingStrategyFactory, POSRuleEngineFacade, JavaPOSDevicesFactory.
Monopoly

CardDeckFacade

The jail-card deck from 6.2.
Tony's Pizza

Two factories and a log

DroneAdapterFactory, AssignmentStrategyFactory and OrderLog (week 9: "a single log for all orders and deliveries").
Elsewhere in Larman

States, logger, dialog

The stateless state objects in the State pattern (OldCleanState.getInstance()), and the logger and dialog in Centralized Error Logging and Error Dialog.

Putting Part VI together: Adapters from a Singleton Factory

Remember Larman's sentence from 6.1, "let's use Adapters generated from a Singleton Factory"? Here it is as a sequence diagram (Larman Fig. 26.8). Three patterns cooperate: the Singleton makes the factory reachable from anywhere, the Factory creates the right adapter, and the Adapter hides the external system.

:Store:ServicesFactory1«actor»:SAPSystemcreate:RegisteraccountingAdapter = getAccountingAdapter()create:SAPAccountingAdapteraccountingAdapterlater: makePayment() creates a Payment, then…postSale(sale)SOAP over HTTP
Three patterns in one interaction. :Register reaches the factory through Singleton (the "1": no getInstance() drawn), the factory creates the SAPAccountingAdapter and hands it back typed as IAccountingAdapter, and later Register calls postSale(sale) without knowing that SOAP over HTTP is involved.

Larman sums up the reasoning behind this design as a chain of principles and patterns: Controller, Creator, Protected Variations, Low Coupling, High Cohesion, Indirection, Polymorphism, Adapter, Factory and Singleton.

Pitfalls (be ready to discuss) exam

The case against Singleton
  • Global state creates hidden dependencies and tight coupling, because every caller is bound to the concrete class.
  • Testability suffers: you can't easily substitute a mock, and state leaks between tests.
  • It mixes two responsibilities: managing its own lifecycle, and its real job.
  • Workshop 11 warns that global access causes problems with the open/closed principle.
  • Thread safety is a concern, both for lazy creation and for mutable state.
  • It is one instance per class loader or JVM, not per distributed system.
  • Serialisation, reflection or cloning can create extra instances.
  • It is easy to overuse as a glorified global variable.
Mitigations

Keep singletons stateless or synchronised, access them through an interface, and prefer passing references (dependency injection) when that is easy.

The past-exam "describe this Java class" question about a Singleton counter, with its official answer, is worked through in Part VII.

Check yourselfSpot the errors: public class Clock { public static Clock instance; public Clock() {} public Clock getInstance() { if (instance == null) instance = new Clock(); return instance; } }

Three errors. (1) The constructor is public, so anyone can write new Clock(); it must be private. (2) getInstance() is not static, so you would need a Clock to get the Clock; it must be public static. (3) The field is public; it should be private static. For multithreaded use, the lazy getInstance() also needs synchronized (or switch to eager initialisation).

Check yourselfA traffic simulation has a simulated time of day that every vehicle, light and sensor must read, and there must never be two clocks. Which pattern, and what is one cost you should mention?

Singleton: "there is only one X" (the simulated time of day) and it is "accessed from many places". SimClock gets a private constructor, a private static instance and a public static getInstance(); now() stays an instance method. A cost to mention: testability, since tests can't easily substitute a fake clock and its state leaks between tests (mitigate by accessing it through an interface, or injecting it).

Check yourselfGive Larman's two reasons for preferring lazy initialisation, and the one thing lazy initialisation needs that eager initialisation doesn't.

Lazy initialisation (1) avoids the creation work, and the cost of holding expensive resources, if the instance is never used, and (2) lets getInstance() contain complex conditional creation logic, such as reading a property to choose a subclass. It needs concurrency control (synchronized) in multithreaded code, because two threads could otherwise both see null and create two instances. Eager initialisation is thread-safe without locks, because the JVM initialises classes safely.

Check yourselfIn a sequence diagram, the factory's lifeline is labelled 1 :ServicesFactory and there is no getInstance() arrow. Is the diagram missing a message?

No. The "1" on the lifeline says the object was reached through Singleton, which makes the getInstance() call implicit (Larman Fig. 26.7). Drawing it is optional; the "1" says it all.

In short
  • Singleton = exactly one instance + a global access point: private constructor, private static field, public static getInstance(), instance service methods.
  • Lazy (Larman's preference: no cost if unused, room for creation logic) needs synchronized; eager is simpler and thread-safe.
  • UML: "1" in the class box corner, underlined statics; a lifeline marked "1" makes getInstance() implicit.
  • Be ready to discuss the costs: global state, testability, thread safety, overuse. Mitigate with interfaces and dependency injection.