๐Ÿš€Transform your business with AI-powered process optimization
Architecture
๐Ÿ’ก Design Patterns
Software Design Patterns
Observer Pattern

Observer Pattern

The Observer Pattern enables AI agents to subscribe to and receive notifications about state changes in other components, facilitating reactive behavior.

Pattern Overview

This pattern defines a one-to-many dependency between objects, so when one object changes state, all dependents are notified automatically.

Structure

use std::collections::HashMap;
 
// Event types
#[derive(Debug, Clone)]
pub enum AgentEvent {
    TaskCompleted(String),
    ErrorOccurred(String),
    StateChanged(String),
}
 
// Observer trait
pub trait Observer {
    fn update(&mut self, event: &AgentEvent);
    fn get_id(&self) -> &str;
}
 
// Subject trait
pub trait Subject {
    fn attach(&mut self, observer: Box<dyn Observer>);
    fn detach(&mut self, observer_id: &str);
    fn notify(&self, event: &AgentEvent);
}
 
// Concrete observer implementation
pub struct MonitoringAgent {
    id: String,
}
 
impl MonitoringAgent {
    pub fn new(id: &str) -> Self {
        Self { id: id.to_string() }
    }
}
 
impl Observer for MonitoringAgent {
    fn update(&mut self, event: &AgentEvent) {
        println!("Monitor {}: Received event {:?}", self.id, event);
    }
 
    fn get_id(&self) -> &str {
        &self.id
    }
}
 
// Concrete subject implementation
pub struct WorkerAgent {
    observers: HashMap<String, Box<dyn Observer>>,
    state: String,
}
 
impl WorkerAgent {
    pub fn new() -> Self {
        Self {
            observers: HashMap::new(),
            state: "idle".to_string(),
        }
    }
 
    pub fn do_work(&mut self, task: &str) {
        self.state = format!("working on {}", task);
        self.notify(&AgentEvent::StateChanged(self.state.clone()));
        
        // Simulate work completion
        self.notify(&AgentEvent::TaskCompleted(task.to_string()));
    }
}
 
impl Subject for WorkerAgent {
    fn attach(&mut self, observer: Box<dyn Observer>) {
        let id = observer.get_id().to_string();
        self.observers.insert(id, observer);
    }
 
    fn detach(&mut self, observer_id: &str) {
        self.observers.remove(observer_id);
    }
 
    fn notify(&self, event: &AgentEvent) {
        for observer in self.observers.values() {
            // Note: This simplified example doesn't show mutable access
            println!("Notifying observer about: {:?}", event);
        }
    }
}

Usage Example

let mut worker = WorkerAgent::new();
let monitor = MonitoringAgent::new("monitor_1");
 
worker.attach(Box::new(monitor));
worker.do_work("data analysis");

Benefits

  • Loose Coupling: Subjects and observers are loosely coupled
  • Dynamic Relationships: Add/remove observers at runtime
  • Broadcast Communication: One-to-many communication pattern
  • Separation of Concerns: Clear separation between core logic and notifications

Use Cases

  • Agent performance monitoring and alerting
  • Event-driven agent communication
  • Logging and auditing agent activities
  • Triggering dependent agent actions