1

I'm learning design patterns with GoFPatterns and trying to do their "Traffic Signals" exercise in Rust.

I came up with a solution:

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum SignalState {
    STOP,
    CAUTION,
    GO,
}

trait TrafficSignal {
    fn change_state(&mut self) {
        match self.get_state() {
            SignalState::STOP => self.set_state(SignalState::GO),
            SignalState::CAUTION => self.set_state(SignalState::STOP),
            SignalState::GO => {
                self.passage_granted();
                self.set_state(SignalState::CAUTION);
            }
        }
    }

    fn request_passage(&mut self) {
        self.set_passage_requested(true);
    }

    fn passage_granted(&mut self) {
        self.set_passage_requested(false);
    }

    fn set_passage_requested(&mut self, new_passage_requested: bool);
    fn set_state(&mut self, new_state: SignalState);

    fn get_state(&self) -> SignalState;
    fn get_passage_requested(&self) -> bool;

    fn get_message(&self) -> String;
}

struct TrafficLight {
    passage_requested: bool,
    state: SignalState,
}

impl TrafficLight {
    fn new() -> Self {
        Self {
            passage_requested: false,
            state: SignalState::STOP,
        }
    }
}

impl TrafficSignal for TrafficLight {
    fn set_passage_requested(&mut self, new_passage_requested: bool) {
        self.passage_requested = new_passage_requested;
    }

    fn set_state(&mut self, new_state: SignalState) {
        self.state = new_state;
    }

    fn get_state(&self) -> SignalState {
        self.state
    }

    fn get_passage_requested(&self) -> bool {
        self.passage_requested
    }

    fn get_message(&self) -> String {
        format!("Traffic Light : {:?}", self.state)
    }
}

struct WalkSign {
    passage_requested: bool,
    state: SignalState,
}

impl WalkSign {
    fn new() -> Self {
        Self {
            passage_requested: false,
            state: SignalState::STOP,
        }
    }
}

impl TrafficSignal for WalkSign {
    fn set_passage_requested(&mut self, new_passage_requested: bool) {
        self.passage_requested = new_passage_requested;
    }

    fn set_state(&mut self, new_state: SignalState) {
        self.state = new_state;
    }

    fn get_state(&self) -> SignalState {
        self.state
    }

    fn get_passage_requested(&self) -> bool {
        self.passage_requested
    }

    fn get_message(&self) -> String {
        format!("Walk Sign : {:?}", self.state)
    }
}

There is a lot of code duplication because in Rust we can't inherit properties, so I create setters and getters for each property to use in the TrafficSignal trait.

How could I do it better?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
zaborghi
  • 31
  • 5
  • 1
    Asking for general improvements to your code is overly broad and off-topic for Stack Overflow so I've removed that part. If you want general feedback and improvements, check out [Code Review](https://codereview.meta.stackexchange.com/questions/5777/a-guide-to-code-review-for-stack-overflow-users). – Shepmaster Nov 15 '20 at 18:54
  • Have you read [Object Oriented Programming Features of Rust in *The Rust Programming Language*](https://doc.rust-lang.org/book/ch17-00-oop.html)? – Shepmaster Nov 15 '20 at 19:03
  • Given that the fields are all identical, you can use a macro to remove the duplication. e.g. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=62b67762cc07434d5f9c3c6c57d27a8c – Peter Hall Nov 15 '20 at 19:06

0 Answers0