Last active
April 27, 2018 18:01
-
-
Save blogscot/0b48f242c5ed84786bfd48cc2221a836 to your computer and use it in GitHub Desktop.
Visitor Pattern Example in Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// | |
/// Each car element accepts a visitor. | |
/// | |
trait CarElement { | |
fn accept(&self, visitor: &CarElementVisitor); | |
} | |
/// | |
/// Each visitor must deal with each element of a car. | |
/// | |
trait CarElementVisitor { | |
fn visit_car(&self, element: &Car); | |
fn visit_body(&self, element: &Body); | |
fn visit_engine(&self, element: &Engine); | |
fn visit_wheel(&self, element: &Wheel); | |
} | |
/// | |
/// A car is a bunch of `elements`. | |
struct Car { | |
pub elements: Vec<Box<CarElement>>, | |
message: String, | |
} | |
impl Car { | |
/// | |
/// Construct a new car. | |
/// | |
fn new() -> Self { | |
let engine: Box<CarElement> = Box::new(Engine { | |
message: "Checking the engine.".to_string(), | |
}); | |
let body: Box<CarElement> = Box::new(Body { | |
message: "Examining the body.".to_string(), | |
}); | |
let wheel_positions = ["front right", "front left", "back right", "back left"]; | |
let wheels: Vec<Box<CarElement>> = wheel_positions | |
.iter() | |
.map(|position| { | |
Box::new(Wheel { | |
position: position.to_string(), | |
}) | |
} as Box<CarElement>) | |
.collect(); | |
let mut elements = vec![engine, body]; | |
elements.extend(wheels); | |
Car { | |
elements, | |
message: "Starting my car.".to_string(), | |
} | |
} | |
} | |
/// | |
/// Treat a car like any car element, that is, | |
/// it can be visited! | |
/// | |
impl CarElement for Car { | |
fn accept(&self, visitor: &CarElementVisitor) { | |
for element in &self.elements { | |
element.accept(visitor); | |
} | |
visitor.visit_car(self); | |
} | |
} | |
struct Body { | |
message: String, | |
} | |
impl CarElement for Body { | |
fn accept(&self, visitor: &CarElementVisitor) { | |
visitor.visit_body(self); | |
} | |
} | |
struct Engine { | |
message: String, | |
} | |
impl CarElement for Engine { | |
fn accept(&self, visitor: &CarElementVisitor) { | |
visitor.visit_engine(self); | |
} | |
} | |
struct Wheel { | |
position: String, | |
} | |
impl CarElement for Wheel { | |
fn accept(&self, visitor: &CarElementVisitor) { | |
visitor.visit_wheel(self); | |
} | |
} | |
/// | |
/// Welcome our first visitor. | |
/// | |
struct PrintVisitor {} | |
impl CarElementVisitor for PrintVisitor { | |
fn visit_car(&self, element: &Car) { | |
println!("{}", element.message); | |
} | |
fn visit_body(&self, element: &Body) { | |
println!("{}", element.message); | |
} | |
fn visit_engine(&self, element: &Engine) { | |
println!("{}", element.message); | |
} | |
fn visit_wheel(&self, element: &Wheel) { | |
println!("Kicking my {} wheel", element.position); | |
} | |
} | |
fn main() { | |
let car = Car::new(); | |
car.accept(&PrintVisitor {}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment