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

Decorator Pattern

The Decorator Pattern adds new functionality to AI agents dynamically without altering their structure, enabling flexible behavior composition.

Pattern Overview

This pattern attaches additional responsibilities to agents dynamically, providing a flexible alternative to subclassing for extending functionality.

Structure

// Base agent trait
pub trait Agent {
    fn process(&self, input: &str) -> String;
}
 
// Concrete base agent
pub struct BasicAgent {
    name: String,
}
 
impl BasicAgent {
    pub fn new(name: &str) -> Self {
        Self {
            name: name.to_string(),
        }
    }
}
 
impl Agent for BasicAgent {
    fn process(&self, input: &str) -> String {
        format!("Basic processing of: {}", input)
    }
}
 
// Base decorator
pub trait AgentDecorator: Agent {
    fn get_wrapped_agent(&self) -> &dyn Agent;
}
 
// Logging decorator
pub struct LoggingDecorator {
    wrapped: Box<dyn Agent>,
}
 
impl LoggingDecorator {
    pub fn new(agent: Box<dyn Agent>) -> Self {
        Self { wrapped: agent }
    }
}
 
impl Agent for LoggingDecorator {
    fn process(&self, input: &str) -> String {
        println!("LOG: Processing input: {}", input);
        let result = self.wrapped.process(input);
        println!("LOG: Result: {}", result);
        result
    }
}
 
// Validation decorator
pub struct ValidationDecorator {
    wrapped: Box<dyn Agent>,
}
 
impl ValidationDecorator {
    pub fn new(agent: Box<dyn Agent>) -> Self {
        Self { wrapped: agent }
    }
 
    fn validate_input(&self, input: &str) -> bool {
        !input.is_empty() && input.len() < 1000
    }
}
 
impl Agent for ValidationDecorator {
    fn process(&self, input: &str) -> String {
        if self.validate_input(input) {
            self.wrapped.process(input)
        } else {
            "Error: Invalid input".to_string()
        }
    }
}
 
// Caching decorator
pub struct CachingDecorator {
    wrapped: Box<dyn Agent>,
    // Simplified cache representation
    cache_enabled: bool,
}
 
impl CachingDecorator {
    pub fn new(agent: Box<dyn Agent>) -> Self {
        Self {
            wrapped: agent,
            cache_enabled: true,
        }
    }
}
 
impl Agent for CachingDecorator {
    fn process(&self, input: &str) -> String {
        if self.cache_enabled {
            // Simplified cache check
            format!("CACHED: {}", self.wrapped.process(input))
        } else {
            self.wrapped.process(input)
        }
    }
}

Usage Example

// Create base agent
let base_agent = BasicAgent::new("ProcessorAgent");
 
// Wrap with decorators
let logged_agent = LoggingDecorator::new(Box::new(base_agent));
let validated_agent = ValidationDecorator::new(Box::new(logged_agent));
let cached_agent = CachingDecorator::new(Box::new(validated_agent));
 
// Use the decorated agent
let result = cached_agent.process("sample data");

Benefits

  • Flexibility: Add/remove behaviors dynamically
  • Composition: Combine multiple decorators
  • Single Responsibility: Each decorator has one purpose
  • Open/Closed: Open for extension, closed for modification

Use Cases

  • Adding logging, validation, and caching to agents
  • Implementing security and authentication layers
  • Performance monitoring and metrics collection
  • A/B testing different agent behaviors