Design patterns: Observer
The Observer Pattern is a behavioral design pattern that defines a one-to-many relationship between objects. When an object changes its state, all the objects observing it (known as observers) are automatically notified and updated. This pattern is useful when you want several objects to react automatically to changes in another object, while keeping loose coupling between the parties involved.
Strengths
- Decoupling: It keeps loose coupling between the observed subject and its observers, promoting modularity and flexibility in the code.
- Automatic Notifications: Observers are notified automatically when the subject changes state, with no need for explicit interaction between subject and observer.
- Easy to Extend: Adding new observers or subjects requires no changes to existing objects, making the system extensible.
- Flexibility: It lets you add observers dynamically at runtime, so you can change the system’s behavior without changing its structure.
- Use in Reactive Systems: It’s ideal for building reactive systems, where one object’s actions need to propagate efficiently and promptly to other objects.
Use Case
Suppose we have a notification system for a blog. When a new article is published, all subscribed users must be notified by email. The blog is the subject that notifies the observers (the registered users) every time there’s a new article.
PHP Code
// Interface for observers
interface Observer {
public function update($article);
}
// Interface for the subject (Blog)
interface Subject {
public function attach(Observer $observer);
public function detach(Observer $observer);
public function notify();
}
// Concrete subject class (Blog)
class Blog implements Subject {
private $observers = [];
private $latestArticle;
public function attach(Observer $observer) {
$this->observers[] = $observer;
}
public function detach(Observer $observer) {
$this->observers = array_filter($this->observers, function($o) use ($observer) {
return $o !== $observer;
});
}
public function publishArticle($article) {
$this->latestArticle = $article;
$this->notify();
}
public function notify() {
foreach ($this->observers as $observer) {
$observer->update($this->latestArticle);
}
}
}
// Concrete observer class (User)
class User implements Observer {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function update($article) {
echo "Notification for {$this->name}: new article published - {$article}\n";
}
}
// Usage example
// Create a new blog
$blog = new Blog();
// Create a few users (observers)
$user1 = new User("Alice");
$user2 = new User("Bob");
// The two users subscribe to the blog's notifications
$blog->attach($user1);
$blog->attach($user2);
// A new article is published
$blog->publishArticle("Introduction to Design Patterns");
/* Output:
Notification for Alice: new article published - Introduction to Design Patterns
Notification for Bob: new article published - Introduction to Design Patterns
*/
Explanation
- Observer: The interface that defines the update() method, which is called every time the subject (the blog) notifies a change.
- Subject: The interface for the observed subject, with the attach(), detach() and notify() methods for managing observers and notifying changes.
- Blog: The concrete class that implements the subject. It maintains a list of observers and notifies them of updates when a new article is published.
- User: The concrete observer class that implements the update() method to receive notifications.