面向对象
面向对象程序由对象组成。一个对象封装了数据和操作这些数据的过程。这些过程通常被称为方法或操作 。
- 带有方法的结构体和枚举,作用与对象相似,但官方刻意不称之为对象
Trait Object
(太几把难学了,跟异步有的一拼。句子都看得懂,代码就看不懂了。以后再回来写。)
根据后文的理解反推:
- 程序有一个正经的结构体(主结构体),用于存放数据(包括对不正经结构体的引用)和实现方法
- 程序有多个不正经的结构体(子结构体),结构体的名字仅用于标记主对象(主结构体的实例)的状态,本身不存储数据
- 子结构体有实现方法,但 impl 内的方法 被 trait 限制,而且是多个子结构体实现同一个 trait
- Trait对象(Trait Object):就是子结构体(不正经结构体)的实例,但通过被主结构体引用来使用内部方法。
- Trait对象作为主对象的状态标记是可以动态分发的,通过改变引用即可改变状态,同时就能改变同名方法的行为。实现了对象在不同状态下,同一函数(只是使用时名字和路径都一样,而且受限于同一个Trait,实际上不是同一个函数)的不同行为。
面向对象的状态实现
教程的其他内容逼逼赖赖的,但一看代码就懂了,跟前面的内容完全反过来了,草。
基于 trait 对象的状态实现
rust
// 定义 Post 结构体,包含状态和内容
pub struct Post {
state: Option<Box<dyn State>>, // 使用 Option<Box<dyn State>> 存储状态对象
content: String, // 博文内容
}
impl Post {
// 创建新的草稿博文
pub fn new() -> Post {
Post {
state: Some(Box::new(Draft {})), // 初始状态为 Draft
content: String::new(), // 初始内容为空
}
}
// 向博文添加文本
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text); // 直接修改内容,不依赖状态
}
// 获取博文内容(根据当前状态返回不同值)
pub fn content(&self) -> &str {
// 调用当前状态的 content 方法
self.state.as_ref().unwrap().content(self)
}
// 请求审核,改变状态
pub fn request_review(&mut self) {
// 取出当前状态(留下 None),然后转移所有权
if let Some(s) = self.state.take() {
// 调用状态的 request_review 方法获取新状态
self.state = Some(s.request_review())
}
}
// 批准发布,改变状态
pub fn approve(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.approve())
}
}
}
// 状态 trait,定义所有状态共有的行为
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
}
}rust
use blog::Post;
fn main() {
let mut post = Post::new();
// 草稿阶段添加内容
post.add_text("I ate a salad for lunch today");
assert_eq!("", post.content()); // 草稿状态内容应为空
// 请求审核
post.request_review();
assert_eq!("", post.content()); // 等待审核状态内容应为空
// 批准发布
post.approve();
assert_eq!("I ate a salad for lunch today", post.content()); // 已发布状态显示内容
}基于类型的状态实现
rust
// 已发布的博文
pub struct Post {
content: String, // 只有发布状态才能访问内容
}
// 草稿博文
pub struct DraftPost {
content: String,
}
// 等待审核的博文
pub struct PendingReviewPost {
content: String,
}
impl Post {
// 创建新的草稿博文(直接返回 DraftPost)
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,
}
}
}
impl PendingReviewPost {
// 从等待审核转为已发布状态
pub fn approve(self) -> Post {
Post {
content: self.content,
}
}
}rust
use blog::Post;
fn main() {
// 创建草稿
let mut post = Post::new();
// 添加内容(只能在草稿阶段)
post.add_text("I ate a salad for lunch today");
// 请求审核(消耗 DraftPost,返回 PendingReviewPost)
let post = post.request_review();
// 批准发布(消耗 PendingReviewPost,返回 Post)
let post = post.approve();
// 现在可以访问内容
assert_eq!("I ate a salad for lunch today", post.content());
}