Observer Pattern: Trade-offs and Alternatives
First, when an abstraction has two aspects where one depends on the other, and you want to encapsulate these aspects in separate objects to vary them independently. Example: a data model (subject) with multiple visualization views (observers).
Second, when a change to one object requires changing others, but you do not know how many objects need to change or what their concrete types are. The observer list is dynamic and determined at runtime.
Third, when an object should be able to notify other objects without making assumptions about who those objects are. This maintains loose coupling and follows the Dependency Inversion Principle.
First, if you have a simple system with only one observer that will never change, direct method calls are more straightforward.
Second, if notification order matters critically, Observer makes this implicit and harder to control.
Third, if the relationship is truly one-to-one, Observer adds unnecessary abstraction.
Cons: Unexpected updates, memory leaks if not detached, ordering issues
Cons: Tight coupling, violates Open/Closed, hard to extend
Use Mediator when: communication between objects becomes complex with many-to-many relationships. Mediator centralizes the interaction logic. Example: a chat room where users send messages through a mediator rather than directly observing each other.
Observer vs Mediator: Observer is one-to-many with subjects not knowing about each other. Mediator is many-to-many where all communication goes through a central coordinator. If your observers need to communicate with each other or coordination logic becomes complex, Mediator is more appropriate.
Alternative: Event Bus (Pub-Sub)Use Event Bus when: you want complete decoupling where publishers do not maintain observer lists. Publishers emit events to a bus, and subscribers register interest in event types. This is Observer at architectural scale with topics/channels.
Observer vs Event Bus: Observer maintains explicit subject-observer relationships with direct references. Event Bus decouples further using a message broker, but adds infrastructure complexity and potential latency. For in-process notifications within a single application, Observer is simpler. For distributed systems or plugin architectures, Event Bus is more suitable.
detach() or use weak references if your language supports them, but note that weak references make it harder to reason about observer lifetime.Notification Cost: If you have N observers, each state change triggers N update calls. For subjects that change frequently (like mouse position), this can become expensive. In such cases, batch notifications or throttle/debounce updates.
Update Consistency: If observers modify subject state during notification, you can trigger cascading updates or infinite loops. Either prohibit observers from modifying subjects during updates, or use a notification queue to process updates in controlled batches.
WeakReference for observer storage can help, but requires careful lifecycle management. In interview settings, explicitly calling detach() in cleanup methods is the clearer approach.