2IRR00 · Topic 08
Creational Patterns
Polymorphism, generics, design patterns, singleton, factory
Polymorphism & generics
Polymorphism = a unit behaving differently depending on context. Generics (parametric polymorphism) let you write type-safe, reusable classes/methods parameterised by a type.
Ad-hoc (overloading): same name, different parameter lists, resolved at COMPILE time. Return type alone cannot distinguish overloads.
Subtyping (overriding): a subclass overrides a method; the actual type is resolved at RUNTIME (dynamic dispatch).
Parametric (generics): ArrayList<E>, GenericPair<K,V> — the compiler checks the type, avoiding runtime ClassCastExceptions.
Generics improve readability, reusability, robustness, and type safety.
List l = new ArrayList(); // raw
l.add("text");
Integer i = (Integer) l.get(0); // RUNTIME error
List<String> ls = new ArrayList<>();
ls.add("text");
Integer j = (Integer) ls.get(0); // compile-time TYPE errorCommon mistakes
- Trying to overload methods by return type only (illegal).
Exam tips
- Three polymorphism forms: ad-hoc (overload, compile-time), subtyping (override, runtime), parametric (generics).
- SwingWorker<T,V> question reuses generics: <ReturnType, IntermediateType>.
Polymorphism & generics practice
1 questions
Design patterns (the big picture)
A design pattern is a reusable, adaptable solution strategy for a recurring design problem. The Gang of Four defined 23 patterns in three families: Creational, Structural, Behavioral.
A pattern is reusable in and adaptable to multiple different contexts — it is NOT 'code'; it's a solution strategy.
Two class diagrams identical except for names can still represent DIFFERENT patterns — intent matters, not just structure (state vs strategy have identical structure!).
Patterns aren't always applicable ('if you only have a hammer, everything looks like a nail'). Using a pattern is not automatically better.
Families: Creational (object creation), Structural (composition/relationships), Behavioral (communication/algorithms).
Common mistakes
- Saying 'a design pattern is code that solves a problem' (false — it's an adaptable strategy).
- Saying a program using a pattern is always preferable (false — patterns can be overkill).
Exam tips
- Correct MCQ statements: a pattern is reusable/adaptable across contexts ✔; identical-looking diagrams can be different patterns ✔.
- Course patterns: Singleton, Factory/Abstract Factory (creational); Decorator, Facade (structural); Command, Observer, Strategy, Iterator, Template Method, State (behavioral) + MVC (architectural).
Design patterns (the big picture) practice
1 questions
Singleton
Singleton restricts a class to a single instance and provides a global access point to it.
Three ingredients: a private static instance, a private constructor, a public static getInstance().
Lazy: create on first call (saves resources, but NOT thread-safe — two threads can both see null and create two instances). Eager: create at class load (thread-safe, but always created).
Make it thread-safe with eager init or a synchronized getInstance().
Downsides: introduces global access (can be misused), violates single-responsibility (manages its own uniqueness + does its job), increases coupling, hurts extensibility and testability.
class PrintScheduler {
private static final PrintScheduler scheduler = new PrintScheduler();
private static Stack<Document> printJobs;
private PrintScheduler() { printJobs = new Stack<>(); } // private ctor
public static PrintScheduler getScheduler() { return scheduler; }
public void printNext() {
if (!printJobs.empty()) printJobs.pop().print();
}
}Common mistakes
- Leaving the constructor public, or the instance non-static/non-private.
- Using lazy init in a threaded context (race condition).
Exam tips
- Singleton problems (MCQ): global access can be misused ✔; mixes responsibilities ✔. NOT 'private constructor makes it hard to reuse' and NOT 'existing once is never good'.
- Code-edit question: private static instance + private constructor + public static getInstance(). The instance need not be final.
Singleton practice
1 questions
Factory & Abstract Factory
A factory defines an interface to create objects but defers the concrete instantiation to subclasses, decoupling object creation from concrete classes.
'new' couples code to a concrete class and violates dependency inversion. A factory hides which concrete class is created and lets subclasses decide.
Enables creating objects whose types are unknown at coding time; supports open/closed (add products/factories without changing clients).
Returned objects are typed as the abstract product — you can store a Car as Vehicle, but assigning it back to a Car variable fails without an explicit cast (the static type is Vehicle).
Abstract Factory: a factory of related families (e.g. EU vs US factory each producing matching Engine + Car).
Used for: GUI/game-engine elements (Swing/JavaFX), loggers, plug-in loading.
Vehicle car1 = reader.getStoredVehicles().get(0); // ✔ Vehicle
Car car2 = reader.getStoredVehicles().get(0); // ✘ returns Vehicle,
// needs a cast to CarCommon mistakes
- Overusing factories (adds abstraction/complexity where 'new' would do).
Exam tips
- Factory decouples creation from the concrete class and avoids the dependency-inversion violation of 'new'.
- Remember the static-type subtlety: factory returns the abstract type.
Factory & Abstract Factory practice
1 questions