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

Singleton Pattern

The Singleton Pattern ensures that certain AI system components have only one instance and provides global access to that instance.

Pattern Overview

This pattern restricts instantiation of a class to one object, useful for coordinating actions across an AI system or managing shared resources.

Structure

use std::sync::{Arc, Mutex, Once};
 
// Configuration manager singleton
pub struct ConfigManager {
    settings: std::collections::HashMap<String, String>,
}
 
impl ConfigManager {
    fn new() -> Self {
        let mut settings = std::collections::HashMap::new();
        settings.insert("agent_timeout".to_string(), "30".to_string());
        settings.insert("max_retries".to_string(), "3".to_string());
        
        Self { settings }
    }
 
    pub fn get_setting(&self, key: &str) -> Option<&String> {
        self.settings.get(key)
    }
 
    pub fn set_setting(&mut self, key: String, value: String) {
        self.settings.insert(key, value);
    }
}
 
// Thread-safe singleton implementation
static INIT: Once = Once::new();
static mut CONFIG_MANAGER: Option<Arc<Mutex<ConfigManager>>> = None;
 
impl ConfigManager {
    pub fn instance() -> Arc<Mutex<ConfigManager>> {
        unsafe {
            INIT.call_once(|| {
                CONFIG_MANAGER = Some(Arc::new(Mutex::new(ConfigManager::new())));
            });
            CONFIG_MANAGER.as_ref().unwrap().clone()
        }
    }
}
 
// Agent registry singleton
pub struct AgentRegistry {
    agents: std::collections::HashMap<String, String>,
}
 
impl AgentRegistry {
    fn new() -> Self {
        Self {
            agents: std::collections::HashMap::new(),
        }
    }
 
    pub fn register_agent(&mut self, id: String, agent_type: String) {
        self.agents.insert(id, agent_type);
    }
 
    pub fn get_agent_type(&self, id: &str) -> Option<&String> {
        self.agents.get(id)
    }
 
    pub fn list_agents(&self) -> Vec<&String> {
        self.agents.keys().collect()
    }
}
 
static REGISTRY_INIT: Once = Once::new();
static mut AGENT_REGISTRY: Option<Arc<Mutex<AgentRegistry>>> = None;
 
impl AgentRegistry {
    pub fn instance() -> Arc<Mutex<AgentRegistry>> {
        unsafe {
            REGISTRY_INIT.call_once(|| {
                AGENT_REGISTRY = Some(Arc::new(Mutex::new(AgentRegistry::new())));
            });
            AGENT_REGISTRY.as_ref().unwrap().clone()
        }
    }
}

Usage Example

// Access configuration manager
let config = ConfigManager::instance();
let timeout = {
    let config_lock = config.lock().unwrap();
    config_lock.get_setting("agent_timeout").cloned()
};
 
// Access agent registry
let registry = AgentRegistry::instance();
{
    let mut registry_lock = registry.lock().unwrap();
    registry_lock.register_agent("agent_1".to_string(), "analysis".to_string());
}

Benefits

  • Global Access: Single point of access to shared resources
  • Resource Control: Prevent multiple instances of expensive resources
  • Consistency: Maintain consistent state across the system
  • Coordination: Central coordination point for system-wide operations

Use Cases

  • Configuration management for AI systems
  • Agent registry and discovery service
  • Database connection pools
  • Logging and monitoring services

Considerations

  • Use sparingly as it can create tight coupling
  • Consider dependency injection as an alternative
  • Ensure thread safety in concurrent environments
  • Be mindful of testing challenges with global state