Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

State #227

Open
Tracked by #116
simonsan opened this issue Feb 22, 2021 · 2 comments
Open
Tracked by #116

State #227

simonsan opened this issue Feb 22, 2021 · 2 comments
Labels
A-pattern Area: Content about Patterns C-addition Category: Adding new content, something that didn't exist in the repository before C-needs discussion Area: Something that is not clear to everyone if it fixes something/adds valuable content

Comments

@simonsan
Copy link
Collaborator

Tracking issue for merging: https://github.com/lpxxn/rust-design-pattern/blob/master/behavioral/state.rs

Example:

//! State is a behavioral design pattern that lets an object alter its behavior when its internal state changes.
//! It appears as if the object changed its class.

//! We’ll implement a blog post workflow
//! 1. A blog post starts as an empty draft.
//! 2. When the draft is done, a review of the post is requested.
//! 3. When the post is approved, it gets published.
//! 4. Only published blog posts return content to print, so unapproved posts can’t accidentally be published.

trait State {
    fn request_review(self: Box<Self>) -> Box<dyn State>;
    fn approve(self: Box<Self>) -> Box<dyn State>;
    fn content<'a>(&self, _post: &'a Post) -> &'a str {
        ""
    }
}

struct Draft;
impl State for Draft {
    fn request_review(self: Box<Draft>) -> Box<dyn State> {
        Box::new(PendingReview {})
    }
    fn approve(self: Box<Draft>) -> Box<dyn State> {
        self
    }
}

struct PendingReview;
impl State for PendingReview {
    fn request_review(self: Box<PendingReview>) -> Box<dyn State> {
        self
    }
    fn approve(self: Box<PendingReview>) -> Box<dyn State> {
        Box::new(Published {})
    }
}

struct Published;
impl State for Published {
    fn request_review(self: Box<Published>) -> Box<dyn State> {
        self
    }
    fn approve(self: Box<Published>) -> Box<dyn State> {
        self
    }
    fn content<'a>(&self, post: &'a Post) -> &'a str {
        &post.content
    }
}

struct Post {
    state: Option<Box<dyn State>>,
    content: String,
}

impl Post {
    fn new() -> Post {
        Post {
            state: Some(Box::new(Draft {})),
            content: String::new(),
        }
    }
    fn add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }
    fn content(&self) -> &str {
        self.state.as_ref().unwrap().content(self)
    }
    fn request_review(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.request_review())
        }
    }
    fn approve(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.approve())
        }
    }
}

fn main() {
    let mut post = Post::new();

    let text = "State is a behavioral design pattern.";
    post.add_text(text);
    assert_eq!("", post.content());

    post.request_review();
    assert_eq!("", post.content());

    post.approve();
    assert_eq!(text, post.content());
    println!("post content: {}", post.content());
}
@simonsan simonsan added C-addition Category: Adding new content, something that didn't exist in the repository before A-pattern Area: Content about Patterns labels Feb 22, 2021
@simonsan
Copy link
Collaborator Author

Tracking discussion on merging: lpxxn/rust-design-pattern#7

@pickfire
Copy link
Contributor

pickfire commented Feb 22, 2021

I talked about this in #100 (comment)

@simonsan simonsan added the C-needs discussion Area: Something that is not clear to everyone if it fixes something/adds valuable content label Feb 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-pattern Area: Content about Patterns C-addition Category: Adding new content, something that didn't exist in the repository before C-needs discussion Area: Something that is not clear to everyone if it fixes something/adds valuable content
Projects
None yet
Development

No branches or pull requests

2 participants