Chain of Responsibility

The Chain of Responsibility pattern is a behavioral design pattern that allows an object to pass a request along a chain of potential handlers until the request is handled.

Here is a simple example of the Chain of Responsibility pattern:

trait Handler {
    fn set_next(&mut self, next: Box<dyn Handler>);
    fn handle(&self, request: &str);
}

struct BaseHandler {
    next: Option<Box<dyn Handler>>,
}

impl BaseHandler {
    fn new() -> Self {
        BaseHandler { next: None }
    }
}

impl Handler for BaseHandler {
    fn set_next(&mut self, next: Box<dyn Handler>) {
        self.next = Some(next);
    }

    fn handle(&self, request: &str) {
        if let Some(ref next) = self.next {
            next.handle(request);
        }
    }
}

struct ConcreteHandlerA {
    next: Option<Box<dyn Handler>>,
}

impl Handler for ConcreteHandlerA {
    fn set_next(&mut self, next: Box<dyn Handler>) {
        self.next = Some(next);
    }

    fn handle(&self, request: &str) {
        if request == "A" {
            println!("ConcreteHandlerA handled request: {}", request);
        } else {
            println!("ConcreteHandlerA passed the request");
            if let Some(ref next) = self.next {
                next.handle(request);
            }
        }
    }
}

struct ConcreteHandlerB {
    next: Option<Box<dyn Handler>>,
}

impl Handler for ConcreteHandlerB {
    fn set_next(&mut self, next: Box<dyn Handler>) {
        self.next = Some(next);
    }

    fn handle(&self, request: &str) {
        if request == "B" {
            println!("ConcreteHandlerB handled request: {}", request);
        } else {
            println!("ConcreteHandlerB passed the request");
            if let Some(ref next) = self.next {
                next.handle(request);
            } 
        }
    }
}


fn main() {
    let mut handler = BaseHandler::new();
    let mut handler_b = Box::new(ConcreteHandlerB { next: None });
    let handler_a = Box::new(ConcreteHandlerA { next: None });

    handler_b.set_next(handler_a);
    handler.set_next(handler_b);

    println!("Handle request A");
    handler.handle("A");
    println!("Handle request B");
    handler.handle("B");
    println!("Handle request C");
    handler.handle("C");
}

In this example:

  • Handler is a trait that defines the interface for handling requests.
  • BaseHandler is a base struct that implements the common behavior for setting the next handler and passing the request along the chain.
  • ConcreteHandlerA and ConcreteHandlerB are concrete implementations of the Handler trait that handle specific requests.
  • The main function sets up the chain and tests the handlers with different requests.