58_实现面向对象的设计模式-状态模式

1. 状态模式

状态模式(state pattern)是一种面向对象的设计模式,一个值拥有的内部状态由数个状态对象(state object)表达而成,而值的行为则随着内部状态的改变而改变。

使用状态模式意味着:业务需求不断变化时,不需要修改持有状态的值的代码,或者使用这个值的代码。只需要更新状态对象内部的代码,以改变其规则。或者增加一些新的状态对象。

看一个案例:分别用状态模式和状态和行为为编码为类型两种方式实现发布博客流程。

2. 状态模式

main.rs

rs 复制代码
use blog::Post;

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

    post.add_text("This is a post.");
    asset_eq!("", post.content());
    post.request_review();
    asset_eq!("", post.content());
    // 审批完成发布
    post.approve();
    asset_eq!("This is a post.", post.content());
}

lib.rs

rs 复制代码
pub 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.content.push_str(text);
    }
    pub fn content(&self) -> &str {
        self.state.as_ref().unwrap().content(&self)
    }
    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());
        }
    }
}

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<Self>) -> Box<dyn State> {
        Box::new(PendingReview {})
    }
    fn approve(self: Box<Self>) -> Box<dyn State> {
        self
    }
}
// 审核
struct PendingReview {}

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

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
		}
}

可以看到状态模式,每个状态维护自身的流程。

缺点:

  • 某些状态之间是相互耦合的
  • 需要重复实现一些逻辑代码

3. 状态和行为编码为类型

结合rust的特点修改上面代码:

将状态编码为不同的类型:

  • Rust 类型检查系统会通过编译时错误来阻止用户使用无效的状态

main.rs

ini 复制代码
use blog::Post;

fn main() {
    let mut post = Post::ngw();
    post.add_text("I ate a salad for lunch today");
    let post = post.request_review();
    let post = post.approve();
    assert_eq!("I ate a salad for lunch today", post.content());
}

lib.rs

rs 复制代码
pub struct Post {
    content: String,
}

pub struct DraftPost {
    content: String,
}
// 发布成功的
impl Post {
    pub fn new() -> DraftPost {
        DraftPost {
            content: String::new(),
        }
    }
    pub fn content(&self) -> &str {
        &self.content
    }
}
// 草稿
impl DraftPost {
    pub fn add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }
    pub fn request_review(self) -> PendingReviewPost {
        PendingReviewPost {
            content: self.content,
        }
    }
}

pub struct PendingReview {
    content: String,
}

impl PendingReview {
    pub fn approve(self) -> Post {
        Post {
            content: self.content,
        }
    }
}

只能在对应的状态做对应的事情,没有提供额外的方法。

4. 总结

Rust不仅能够实现面向对象的设计模式,还可以支持更多的模式。例如:将状态和行为编码为类型;面向对象的经典模式并不总是Rust编程实践中的最佳选择,因为Rust具有所有权等其它面向对象语言没有的特性!

相关推荐
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb5 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角5 小时前
CSS 颜色
前端·css
浪浪山小白兔7 小时前
HTML5 新表单属性详解
前端·html·html5
lee5767 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579657 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
limit for me8 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者8 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
qq_392794488 小时前
前端缓存策略:强缓存与协商缓存深度剖析
前端·缓存