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具有所有权等其它面向对象语言没有的特性!

相关推荐
懒大王爱吃狼38 分钟前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風5 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫5 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
尚梦6 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子6 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山7 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
hikktn7 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust
睡觉谁叫~~~7 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust
音徽编程7 小时前
Rust异步运行时框架tokio保姆级教程
开发语言·网络·rust
毕业设计制作和分享7 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis