Cambridge 9618 · International A Level Computer Science · ~17 min read
Notes
Video
Slides
Quiz
Worksheet
What are Design Patterns?
A design pattern is a reusable, proven solution to a commonly occurring problem in software design. Patterns are not finished code — they are templates that guide how to structure classes and their relationships to solve a specific type of problem.
Design patterns fall into three categories:
Creational
How objects are created.
Examples: Singleton, Factory, Builder
Structural
How classes are composed/structured.
Examples: Adapter, Decorator, Facade
Behavioural
How objects communicate.
Examples: Observer, Strategy, Command
Cambridge 9618 focuses on two key patterns: Singleton (creational) and Observer (behavioural).
The Singleton Pattern
The Singleton pattern ensures that a class has only one instance throughout the program, and provides a global access point to that instance. It is used when exactly one object is needed to coordinate actions across the system.
Real-world use cases
Database connection pool — one shared connection, not one per class
Logger — all parts of the system write to a single log
Configuration manager — one settings object loaded once
Print spooler — all print jobs go through one spooler
How it works
Singleton — three components
Private constructor — prevents external code from calling NEW Database() directly. Only the class itself can create an instance.
↓
Private static instance — a class-level variable (not per-object) that holds the single instance. Starts as NULL/undefined.
↓
Public static getInstance() — the only way to get the object. Checks if instance is NULL; if so creates it (lazy instantiation); always returns the same instance.
// Private constructor — cannot be called from outside PRIVATE PROCEDURENEW() connectionString ← "server=localhost;db=mydb" ENDPROCEDURE
// Public static factory method — the only way to get an instance PUBLIC STATIC FUNCTIONgetInstance() RETURNSDatabaseConnection IFinstance = NULLTHEN instance ← NEWDatabaseConnection() // lazy creation ENDIF RETURNinstance ENDFUNCTION
PUBLIC FUNCTIONquery(sql : STRING) RETURNSSTRING // execute the SQL query and return results ENDFUNCTION ENDCLASS
// Usage — always the same object returned db1 ← DatabaseConnection.getInstance() db2 ← DatabaseConnection.getInstance() // db1 and db2 are the same object — only one was ever created
Underline indicates STATIC (class-level) attribute or method
The Observer Pattern
The Observer pattern defines a one-to-many dependency between a Subject (also called Publisher or Observable) and multiple Observers (also called Subscribers or Listeners). When the Subject changes state, all registered Observers are automatically notified and updated.
PUBLIC PROCEDUREnotify() FORi ← 1TOcount observers[i].update(price) NEXTi ENDPROCEDURE
PUBLIC PROCEDUREsetPrice(p : REAL) price ← p notify() // automatically notify all observers ENDPROCEDURE ENDCLASS
// Concrete observer CLASSPhoneAlertINHERITSObserver PUBLIC PROCEDUREupdate(newValue : REAL) OUTPUT"Alert: price changed to " + newValue ENDPROCEDURE ENDCLASS
Pattern comparison
Feature
Singleton
Observer
Category
Creational
Behavioural
Purpose
Ensure only one instance exists
Notify many objects of a state change
Key mechanism
Private constructor + static getInstance()
register/notify/update methods
Coupling
Tight — all code goes to one object
Loose — subject doesn't know observer details
Use when
Shared resource with one instance needed
Multiple objects need to react to one change
Cambridge 9618 exam tip: Be able to: (1) explain why the Singleton constructor is private — to prevent external code from creating additional instances; (2) explain lazy instantiation — the instance is only created on the FIRST call to getInstance(), not when the class is loaded; (3) describe the Observer roles — Subject holds the list and calls notify(); Observer interface defines update(); concrete observers implement update() with their specific response; (4) describe a real-world scenario for each pattern. Questions often give a scenario and ask you to identify which pattern applies and justify your answer.
⚠️ Common Mistakes
Making the Singleton instance attribute non-static — the instance variable MUST be STATIC (class-level, not per-object) so it persists across all calls to getInstance() and is shared by all references to the class.
Making the Singleton constructor public — a public constructor defeats the pattern, as external code could still call NEW DatabaseConnection() directly. The constructor must be PRIVATE.
Confusing the Subject and Observer roles — the Subject maintains the list of observers and calls notify(). Observers implement the update() method. The subject should not know the concrete type of each observer — it calls update() through the Observer interface.
Saying Observer creates "copies" of data — the Subject doesn't copy data to each observer. It calls each observer's update() method and passes the new value. Each observer then decides independently what to do with the new value.
Forgetting that Observer uses polymorphism — when Subject calls observers[i].update(price), this is polymorphism: PhoneAlert, TradingScreen, and AnalyticsLogger each have their own update() implementation. The Subject doesn't need to know which concrete type each observer is.
✅ Notes completed!
▶
Video coming soon
Click slide or press arrow keys to navigate
Worksheet — 4.2.2 Design Patterns
8 questions · Cambridge 9618 standard
Q1Explain what a design pattern is. State the three categories of design pattern and give one example of a pattern from each category.[4]
✅ Mark scheme
A design pattern is a reusable, general solution to a commonly occurring problem in software design — a template for solving a known type of problem, not finished code [1]; Creational: how objects are created — example: Singleton, Factory [1]; Structural: how classes and objects are composed/combined — example: Adapter, Decorator [1]; Behavioural: how objects communicate and distribute responsibility — example: Observer, Strategy [1].
Q2Explain why the Singleton pattern uses (a) a private constructor, and (b) a static getInstance() method. What is meant by lazy instantiation?[4]
✅ Mark scheme
(a) Private constructor: prevents external code from creating instances by calling NEW directly — only the class itself can call NEW [1]; this guarantees no additional instances are created outside the class, enforcing the single-instance rule [1]. (b) Static getInstance() method: a class-level (not per-object) method that provides the only way to access the single instance; it checks if the instance has been created and creates it if not, otherwise returns the existing one [1]. Lazy instantiation: the single instance is not created when the class is first loaded — it is only created on the FIRST call to getInstance(); this saves memory if the singleton is never needed [1].
Q3Describe the roles of Subject and Observer in the Observer pattern. Explain what happens when the Subject's state changes.[4]
✅ Mark scheme
Subject: maintains a list of registered Observer objects; provides methods to register() and remove() observers; when its state changes, calls notify() which calls update() on each observer [1]; Observer: defines an interface with an update() method; each concrete observer implements update() with its specific response to the state change [1]; when the Subject's state changes (e.g. setPrice() is called): it updates its internal state; it calls notify() which loops through the observer list and calls update(newValue) on each; each observer then independently decides what to do — e.g. display the new price, send an alert, log it [1]; the Subject does not need to know the concrete types of its observers — it communicates through the Observer interface, giving loose coupling [1].
Q4Give two distinct real-world scenarios where the Singleton pattern would be appropriate. Explain why Singleton is suitable in each case.[4]
✅ Mark scheme
Any two of: Database connection pool: only one set of connections should exist to prevent resource waste; multiple modules should share the same pool rather than each creating their own [1][1]; Logger: all parts of the system should write to the same log file; multiple loggers would produce fragmented or duplicate logs [1][1]; Configuration manager: system settings should be loaded once from file and shared; multiple instances could have different cached settings causing inconsistency [1][1]; Print spooler: all print jobs must be queued through one spooler to manage printer access; multiple spoolers would conflict [1][1]. Award 1 mark for each scenario + 1 mark for valid explanation of why Singleton is suitable.
Q5Explain how polymorphism is used in the Observer pattern. Why is this beneficial for adding new observer types?[3]
✅ Mark scheme
All concrete observers (PhoneAlert, TradingScreen, AnalyticsLogger) implement the same Observer interface/superclass and override the update() method [1]; the Subject holds a list typed as Observer (the superclass/interface), so it can store any concrete observer regardless of its actual type; when it calls observers[i].update(price), polymorphism means the correct concrete implementation runs for each observer — this is runtime/dynamic polymorphism [1]; benefit: to add a new observer type (e.g. EmailAlert), you simply create a new class that implements Observer and override update(); no changes needed to the Subject or any existing observer class — the system is open for extension without modification [1].
Q6A social media app has one notification manager that routes all alerts. Multiple features (likes, comments, messages) register to receive alerts. Identify which design pattern applies to each requirement and justify your answer.[4]
✅ Mark scheme
"One notification manager" → Singleton pattern: there should be exactly one NotificationManager instance; making it Singleton ensures all parts of the app use the same manager — not multiple competing managers; implement with private constructor and static getInstance() [1][1]; "Multiple features register to receive alerts" → Observer pattern: the NotificationManager is the Subject; the features (LikeModule, CommentModule, MessageModule) are Observers that register with the manager; when an event occurs, the manager calls notify() → each module's update() runs its specific alert logic [1][1].
Q7Describe the Observer design pattern. Identify the roles of: Subject, Observer interface, and ConcreteObserver. Then write Cambridge 9618 pseudocode for a WeatherStation (Subject) that maintains a list of Observer objects and calls their Update() method when temperature changes.[5]
✅ Mark scheme
Observer pattern: Subject maintains list of Observers; notifies all observers when its state changes — decouples data source from consumers [1]; Subject role: holds observer list, provides Register/Unregister and Notify methods; Observer interface: defines Update() contract; ConcreteObserver: implements Update() with specific reaction [1]; CLASS WeatherStation; PRIVATE observers : ARRAY OF Observer; PRIVATE temperature : REAL [1]; PUBLIC PROCEDURE Register(o:Observer) — add to observers array [1]; PUBLIC PROCEDURE SetTemperature(t:REAL) temperature←t; FOR EACH obs IN observers obs.Update(temperature) NEXT ENDPROCEDURE [1].
Q8A weather application needs exactly one WeatherData object shared across the whole system. (a) Name the design pattern that solves this. (b) Explain the mechanism it uses to enforce a single instance. (c) Write pseudocode for the GetInstance() method that returns the single instance.[4]
✅ Mark scheme
(a) Singleton pattern [1]; (b) The constructor is PRIVATE so external code cannot call NEW WeatherData(); a class-level (static) variable holds the single instance; a PUBLIC class method GetInstance() checks if the instance is NULL — if so, creates it; otherwise returns the existing instance [1]; (c) PUBLIC FUNCTION GetInstance() RETURNS WeatherData; IF instance = NULL THEN instance ← NEW WeatherData() ENDIF; RETURN instance ENDFUNCTION [2].
Topic Quiz
Question 1 of 10
You scored
out of 10
Card 1 of 8
Click to reveal definition
🎉
All cards reviewed!
Term
Definition
🎯
Mini Test — 4.2.2 Design Patterns
10 questions · 10 marks · 10 minutes
⏱ 10:00
Section A — Multiple Choice [5 marks]
Q1The Singleton pattern belongs to which category of design patterns?
Q2In the Singleton pattern, why must the constructor be PRIVATE?
Q3In the Observer pattern, what is the role of the Subject class?
Q4What does "lazy instantiation" mean in the Singleton pattern?
Q5The Observer pattern is best described as which type of relationship?
Section B — Short Answer [5 marks]
Q6A website tracks visitor count. Multiple analytics dashboards need to update whenever the count changes. Identify the most appropriate design pattern and describe how it would be applied.
Mark schemeObserver pattern [1]; the VisitorCounter is the Subject — it holds the visitor count and maintains a list of registered dashboards [1]; each dashboard (AnalyticsDashboard, AdminPanel, etc.) is a concrete Observer implementing update(newCount) [1]; when the visitor count changes, setCount() is called → notify() loops through all registered observers → each calls update(newCount) → each dashboard refreshes its display independently [1].
Q7Write pseudocode for the getInstance() method of a Singleton class called Logger.
Mark schemePUBLIC STATIC FUNCTION getInstance() RETURNS Logger [1 — correct signature]; IF instance = NULL THEN instance ← NEW Logger() ENDIF; RETURN instance [1 — correct logic with null check and lazy creation].
Q8Explain one advantage and one disadvantage of the Singleton pattern.
Mark schemeAdvantage: guarantees exactly one instance of the resource; provides a global access point; saves memory as only one object is created; prevents inconsistency caused by multiple instances [1]; Disadvantage: creates tight coupling — all code that uses the singleton depends on it directly, making testing and modification harder; violates Single Responsibility Principle (the class controls both its own instantiation AND its functionality); can be a bottleneck if many classes depend on it; makes unit testing harder as the global state persists between tests [1].
Q9How does the Observer pattern achieve loose coupling between the Subject and its Observers?
Mark schemeThe Subject only knows about the Observer interface (or abstract class) — it does NOT know the concrete types of its observers [1]; the Subject calls update() through the Observer interface polymorphically — PhoneAlert, TradingScreen, and AnalyticsLogger can all be stored in the same list typed as Observer [1]; this means the Subject can notify any number of different observer types without being changed; new observer types can be added without modifying the Subject at all [1].
Q10Explain what must be true about the instance attribute in a Singleton class and why.
Mark schemeThe instance attribute must be STATIC (class-level) [1]; a static attribute belongs to the class itself, not to any particular object — it is shared across all code that references the class; this means the same instance variable persists between all calls to getInstance(); if it were a regular (non-static) instance variable, each object would have its own instance variable which would be meaningless since we're trying to have only one object [1].