Design Patterns
A design pattern is a tried and true, reusable solution to a repeating software design problem. A design pattern is not a code, but a template or guideline that can structure code in the most effective way.
Benefits of design pattern are --
- Code Reusability
- Provide standardized solutions that can be reused across multiple modules and projects.
Less repeated code and reduced bugs because the logic exists in one place.
Example:
The Factory Pattern lets you reuse the same object creation logic for different classes.
Instead of writing new code every time you create an object, the factory handles it.
- Scalability
Patterns make it easy to extend your system without rewriting existing code.
You can scale features, add components, or support new requirements without modifying the core logic.
Example:
With Observer Pattern, you can add new subscribers easily as the system grows.
- Maintainability
Encourage separation of concerns, meaning each class has one purpose.
When something breaks, debugging becomes easier because the responsibility is clearly isolated. Developers can fix or update parts of the system without worrying about side effects.
Example:
The MVC Pattern separates business logic, UI, and data layers.
- Readability
Design patterns provide well-understood structures that most developers easily recognize.
New team members can understand the system faster.
Code becomes self-explanatory because the architecture follows familiar patterns.
Example:
If another developer sees a code, they immediately understand what’s happening.
Design patterns reduce “mystery code” and bring clarity to large projects.
Types of Design Patterns (3 Main Categories)
| Category | Description | Example Pattern |
|---|---|---|
| Creational | How objects are created and managed | Singleton, Factory |
| Structural | How classes and objects are composed | Adapter, Decorator |
| Behavioral | How objects communicate | Observer, Strategy |
Real-Life Examples (with PHP/Drupal relevance)
1. Singleton Pattern – One Instance Only
Problem: You need one instance of a class across your entire application (e.g., database connection).
Real-life example: Think of a printer spooler - multiple print requests, but only one printer managing them.
Used in Drupal services to manage shared resources like cache, logger, or DB connections.
2. Factory Pattern – Object Creation Logic in One Place
Problem: You need to create objects without exposing creation logic everywhere.
Real-life example: Car factory produces cars — you request a car, not the details of how it’s assembled.
class ShapeFactory {
public static function create($type) {
switch ($type) {
case 'circle': return new Circle();
case 'square': return new Square();
default: throw new Exception('Unknown shape');
}
}
}
Used in Drupal plugin managers — they dynamically create plugin objects based on configuration.
3. Observer Pattern – Event-Based Notifications
Problem: Many parts of your system need to react when something happens.
Real-life example: You subscribe to a YouTube channel. When the creator uploads a video, all subscribers get notified.
In Drupal:
a) Event Dispatcher system works on this pattern.
b) When a node is saved, multiple event subscribers (modules) can react.
// Example: Custom event subscriber in Drupal.
class NodeSaveSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [NodeEvents::INSERT => 'onNodeInsert'];
}
public function onNodeInsert(NodeEvent $event) {
$node = $event->getNode();
// Perform actions after node creation.
}
}3. Decorator Pattern – Add Functionality Dynamically
Problem: You want to enhance behavior without altering the original class.
Real-life example: A coffee shop — you start with plain coffee and add milk, sugar, cream — each decorates the original coffee.
Used in Drupal render arrays and service decoration (e.g., altering core service behavior).
interface Coffee {
public function cost();
}
class SimpleCoffee implements Coffee {
public function cost() { return 50; }
}
class MilkDecorator implements Coffee {
protected $coffee;
public function __construct(Coffee $coffee) { $this->coffee = $coffee; }
public function cost() { return $this->coffee->cost() + 20; }
}