Design Pattern (23) Observer Pattern: Smart Security System One-to-Many Notification Mechanism, Implementing Real-time Alert Broadcasting
You can download the Design Pattern series code from this design_pattern repo.
Requirements
Imagine you are designing a home security system. Our task is to design a Security System Panel, which acts as the brain of the entire security system.
Specific requirements are as follows:
- The panel monitors different sensors, such as smoke detectors or door/window sensors
- When an alarm is triggered, the panel needs to immediately notify all registered devices
- Notification targets include different types of devices such as tablets, iOS phones, and Android phones
- Devices can dynamically join or leave the notification list, ensuring system flexibility
This scenario is very common in real life. Whenever sensors detect abnormal conditions, we want all related devices to receive alert notifications in real-time.
Object-Oriented Analysis (OOA)
After understanding the requirements, letās begin object-oriented analysis. Through analysis, we can see the system structure and relationships between components more clearly.

Recognizing Forces
When designing this security system, what problems would we encounter if we donāt use appropriate design patterns? Letās analyze the potential challenges:
-
High Coupling
If the panel directly interacts with each device, the code becomes difficult to maintain. Imagine that every time we add or remove devices, we need to modify the panelās core logic, making the system very fragile.
-
Lack of Flexibility
When we want to add a new type of device, we must modify existing code. This violates the Open-Closed Principle (OCP) in software design, which states āopen for extension, closed for modification.ā
-
Inconsistent Notifications
In emergency situations, how do we ensure that every device receives alert notifications correctly and timely? If notification mechanisms donāt have unified standards, omissions or errors easily occur.
These problems all point to a core issue: we need a solution that can effectively manage āone-to-manyā relationships.
Applying Observer Pattern (Solution) to Get New Context (Resulting Context)
After completing OOA analysis and recognizing Forces, we now clearly understand the entire problem context. Next, letās apply the Observer Pattern to solve this problem.
Core Concepts of Observer Pattern
First, letās look at the standard UML structure of Observer Pattern:

Observer Pattern provides an elegant one-to-many notification mechanism. When the subjectās state changes, it automatically notifies all subscribed observers.
Observer Pattern, along with Strategy Pattern and State Pattern, belongs to behavioral design patterns, but Observer Pattern focuses on communication between objects and event handling mechanisms.
Letās understand each roleās responsibilities:
- Subject: Security system panel, responsible for managing all devices and sending notifications when alarms are triggered
- Observer: Various devices, such as tablets, iOS and Android phones, responsible for receiving notifications and executing corresponding operations
- ConcreteSubject: Actual security system panel implementation, containing complete alarm logic
- ConcreteObserver: Specific device implementations, such as Android devices or iOS devices
Application to Our Security System
Now letās apply Observer Pattern to our security system application:

Through this design, we solve all previously identified problems. The panel no longer needs to directly depend on each specific device, but communicates through unified interfaces.
Implementation
Now letās convert Observer Pattern design into actual code. Weāll implement each component step by step and explain their functionality.
Subject Interface: AlarmSystem
First define the subject interface, which specifies basic functionality that alarm systems must have:
interface AlarmSystem {
fun addObserver(observer: Device)
fun removeObserver(observer: Device)
fun notifyObservers(alarmMessage: String)
}
This interface defines three core methods: add observer, remove observer, and notify all observers.
Observer Interface: Device
Next define the observer interface, representing all devices that can receive alarm notifications:
interface Device {
fun onAlarmTriggered(alarmMessage: String)
}
Each device must implement the onAlarmTriggered
method to handle received alarm messages.
ConcreteSubject: SecurityPanel
Now implement the concrete security system panel:
class SecurityPanel : AlarmSystem {
private val devices = mutableListOf<Device>()
override fun addObserver(observer: Device) {
devices.add(observer)
}
override fun removeObserver(observer: Device) {
devices.remove(observer)
}
override fun notifyObservers(alarmMessage: String) {
for (device in devices) {
device.onAlarmTriggered(alarmMessage)
}
}
fun triggerAlarm(zone: String) {
val message = "Alarm triggered in $zone!"
println("Panel notification: $message")
notifyObservers(message)
}
}
SecurityPanel
maintains a device list and provides functionality to add, remove, and notify devices. When an alarm is triggered, it automatically notifies all registered devices.
ConcreteObserver: Various Devices
Next implement different types of devices:
class Tablet : Device {
override fun onAlarmTriggered(alarmMessage: String) {
println("Tablet received notification: $alarmMessage")
}
}
class IOSDevice : Device {
override fun onAlarmTriggered(alarmMessage: String) {
println("iOS device received notification: $alarmMessage")
}
}
class AndroidDevice : Device {
override fun onAlarmTriggered(alarmMessage: String) {
println("Android device received notification: $alarmMessage")
}
}
Each device type implements the same interface but can execute different processing logic according to its own characteristics.
Client Test Program
Finally, letās see how to use this system:
fun main() {
val securityPanel = SecurityPanel()
val tablet = Tablet()
val iosDevice = IOSDevice()
val androidDevice = AndroidDevice()
// add observers
securityPanel.addObserver(tablet)
securityPanel.addObserver(iosDevice)
securityPanel.addObserver(androidDevice)
// trigger alarm
securityPanel.triggerAlarm("Living Room")
securityPanel.triggerAlarm("Kitchen")
// remove observer
securityPanel.removeObserver(androidDevice)
securityPanel.triggerAlarm("Bedroom")
}
This test program demonstrates the complete system flow: registering devices, triggering alarms, and dynamic device removal functionality.
Execution Results
Letās see this programās execution output:
Panel notification: Alarm triggered in Living Room!
Tablet received notification: Alarm triggered in Living Room!
iOS device received notification: Alarm triggered in Living Room!
Android device received notification: Alarm triggered in Living Room!
Panel notification: Alarm triggered in Kitchen!
Tablet received notification: Alarm triggered in Kitchen!
iOS device received notification: Alarm triggered in Kitchen!
Android device received notification: Alarm triggered in Kitchen!
Panel notification: Alarm triggered in Bedroom!
Tablet received notification: Alarm triggered in Bedroom!
iOS device received notification: Alarm triggered in Bedroom!
From the output results, we can see that after the Android device was removed, the last alarm only notified the tablet and iOS device. This perfectly demonstrates the Observer Patternās dynamic management capability.
Conclusion
Through Observer Pattern implementation, we successfully constructed a flexible and extensible security system notification mechanism. This solution brings multiple significant advantages:
Main Advantages
- Low Coupling: The panel communicates with various devices through abstract interfaces, reducing dependency relationships between them
- High Extensibility: New device types can be easily added without modifying existing panel logic
- Dynamic Management: Devices can dynamically join or leave notification lists at runtime
- Complies with OCP Principle: Open for extension, closed for modification, conforming to software design best practices
Practical Application Scenarios
Observer Pattern has wide applications in the real world, particularly suitable for the following scenarios:
- Real-time Alert Systems: Like our implemented security system, needing to notify multiple devices simultaneously
- Message Push Systems: Applications needing to send notifications to multiple users simultaneously
- Event Distribution Systems: Event handling in GUI programs, or state updates in games
- Data Monitoring Systems: When data changes occur, needing to update multiple display components
The core value of this pattern lies in establishing a standardized communication mechanism, allowing systems to elegantly handle one-to-many notification requirements.
In the behavioral design pattern learning path, Observer Pattern works together with Command Pattern, Mediator Pattern and other patterns to collectively construct complete object interaction and communication frameworks. Mastering Observer Pattern will significantly enhance your ability to design real-time responsive systems.
Enjoy Reading This Article?
Here are some more articles you might like to read next: