Example: Post
Using Enum
enum PostState {
Draft,
PendingReview,
Published,
}
struct Post {
text: String,
state: PostState,
}
impl Post {
fn new() -> Self {
Post {
text: String::new(),
state: PostState::Draft,
}
}
fn add_text(&mut self, s: &str) {
self.text.push_str(s)
}
fn request_review(&mut self) {
self.state = PostState::PendingReview
}
fn approve(&mut self) {
self.state = PostState::Published
}
fn content(&self) -> &str {
if let PostState::Published = self.state {
&self.text
} else {
""
}
}
}
fn main() {
let mut post = Post::new();
post.add_text("I need sex.");
println!("content: {}", post.content());
post.request_review();
post.approve();
println!("content: {}", post.content());
}
## content:
## content: I need sex.
Using the State Pattern
trait State {
fn add_text(&self, post: &mut String, text: &str) {
println!("Cannot add text!")
}
fn request_review(self: Box<Self>) -> Box<dyn State>;
fn approve(self: Box<Self>) -> Box<dyn State>;
fn reject(self: Box<Self>) -> Box<dyn State>;
fn content<'a>(&self, post: &'a Post) -> &'a str {
""
}
}
struct Draft {}
struct PendingReview {
count: usize,
}
struct Published {}
impl State for Draft {
fn add_text(&self, post: &mut String, text: &str) {
post.push_str(text)
}
fn request_review(self: Box<Self>) -> Box<dyn State> {
Box::new(PendingReview { count: 0 })
}
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
fn reject(self: Box<Self>) -> Box<dyn State> {
self
}
}
impl State for PendingReview {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<dyn State> {
let i = self.count + 1;
if i > 1 {
Box::new(Published {})
} else {
Box::new(PendingReview { count: i })
}
}
fn reject(self: Box<Self>) -> Box<dyn State> {
Box::new(Draft {})
}
}
impl State for Published {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
fn content<'a>(&self, post: &'a Post) -> &'a str {
&post.content
}
fn reject(self: Box<Self>) -> Box<dyn State> {
self
}
}
struct Post {
state: Option<Box<dyn State>>,
content: String,
}
impl Post {
pub fn new() -> Post {
Post {
state: Some(Box::new(Draft {})),
content: String::new(),
}
}
pub fn add_text(&mut self, text: &str) {
self.state
.as_ref()
.unwrap()
.add_text(&mut self.content, text)
}
pub fn request_review(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.request_review())
}
}
pub fn approve(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.approve())
}
}
pub fn reject(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.reject())
}
}
pub fn content(&self) -> &str {
self.state.as_ref().unwrap().content(self)
}
}
fn main() {
let mut post = Post::new();
post.add_text("Hello world!");
println!("content: '{}'", post.content());
post.request_review();
post.reject();
post.request_review();
post.add_text("Hello?"); // cannot add text
post.approve();
post.approve();
println!("content: '{}'", post.content());
}
## content: ''
## Cannot add text!
## content: 'Hello world!'