Design patterns are proven, reusable solutions to common software design problems — a shared vocabulary developers use to communicate design intent quickly ('use a Factory here') instead of re-explaining the same structure from scratch every time. Creational patterns specifically deal with object creation mechanisms.
Singleton ensures a class has only one instance, globally accessible throughout the program:
class DatabaseConnection {
private static instance = null
private function __construct() { /* expensive setup */ }
static function getInstance() {
if DatabaseConnection.instance == null:
DatabaseConnection.instance = new DatabaseConnection()
return DatabaseConnection.instance
}
}
db1 = DatabaseConnection.getInstance()
db2 = DatabaseConnection.getInstance()
// db1 and db2 are the exact same object
The private constructor prevents new DatabaseConnection() from outside; getInstance() is the only way in, and it always returns the same object. Use with caution: Singleton is one of the most overused and criticized patterns — it introduces hidden global state, makes unit testing harder (you can't easily substitute a fake instance), and creates implicit coupling between unrelated parts of a codebase. Modern guidance often prefers Dependency Injection (from the SOLID chapter) to manage a single shared instance instead.
Factory Method delegates object creation to a dedicated method rather than calling new directly everywhere, useful when the exact class to instantiate depends on some condition or should be decided in one central place:
interface Shape { function draw() }
class Circle implements Shape { function draw() { print("Drawing circle") } }
class Square implements Shape { function draw() { print("Drawing square") } }
class ShapeFactory {
static function create(type): Shape {
if type == "circle": return new Circle()
if type == "square": return new Square()
throw Error("Unknown shape type")
}
}
shape = ShapeFactory.create("circle") // caller doesn't need to know the concrete class name
shape.draw()
This keeps object-creation logic centralized and consistent with the Open/Closed Principle: adding a new shape means adding a new case in the factory and a new class, without touching every place that previously called new Circle() or new Square() directly.