Decorator Pattern

Dynamically adds new behaviors or responsibilities to an object by wrapping it in a decorator class. It provides a flexible alternative to subclassing for extending functionality.

Example


// Define a trait representing the Component interface
trait Beverage {
    fn get_description(&self) -> String;
    fn get_cost(&self) -> f64;
}

// Implementation of a concrete Component
struct Coffee;

impl Beverage for Coffee {
    fn get_description(&self) -> String {
        "Coffee".to_string()
    }

    fn get_cost(&self) -> f64 {
        1.0
    }
}

// Implementation of a decorator
struct Milk {
    beverage: Box<dyn Beverage>,
}

impl Milk {
    fn new(beverage: Box<dyn Beverage>) -> Self {
        Milk { beverage }
    }
}

impl Beverage for Milk {
    fn get_description(&self) -> String {
        format!("{} with Milk", self.beverage.get_description())
    }

    fn get_cost(&self) -> f64 {
        self.beverage.get_cost() + 0.5
    }
}

// Implementation of another decorator
struct Sugar {
    beverage: Box<dyn Beverage>,
}

impl Sugar {
    fn new(beverage: Box<dyn Beverage>) -> Self {
        Sugar { beverage }
    }
}

impl Beverage for Sugar {
    fn get_description(&self) -> String {
        format!("{} with Sugar", self.beverage.get_description())
    }

    fn get_cost(&self) -> f64 {
        self.beverage.get_cost() + 0.25
    }
}

fn main() {
    // Create a base component
    let coffee = Box::new(Coffee);

    // Decorate the component with Milk
    let coffee_with_milk = Box::new(Milk::new(coffee));

    // Decorate the component with Sugar
    let coffee_with_milk_and_sugar = Box::new(Sugar::new(coffee_with_milk));

    // Get the final description and cost of the decorated beverage
    println!("Description: {}", coffee_with_milk_and_sugar.get_description());
    println!("Cost: ${}", coffee_with_milk_and_sugar.get_cost());
}