هام : لقراءة المقال بشكل مريح ، يجب أن تكون قادرًا على قراءة الكود المصدري بلغة Rust وفهم سبب Rc<RefCell<...>>سوء تغليف كل شيء .
المقدمة
لا يعتبر الصدأ بشكل عام لغة كائنية التوجه: لا يوجد وراثة تنفيذية ؛ للوهلة الأولى ، لا يوجد تغليف أيضًا ؛ وأخيرا، الرسوم البيانية التبعية للكائنات قابلة للتغيير مألوفة جدا لOOP-الأتباع تبدو كما القبيح ممكن (مجرد إلقاء نظرة على كل هذه Rc<RefCell<...>>و Arc<Mutex<...>>!)
صحيح ، لقد تم اعتبار وراثة التنفيذ ضارة لعدة سنوات بالفعل ، ويقول معلمو OOP أشياء صحيحة جدًا مثل "الكائن الجيد هو كائن غير قابل للتغيير". لذلك كنت أتساءل: كيف جيدا هل التفكير كائن والصدأ حقا تناسب معا ؟
سيكون أول خنزير غينيا هو نمط الحالة ، والتنفيذ الخالص له هو موضوع هذه المقالة.
تم اختياره لسبب: فصل من The Rust Book مخصص لنفس النمط . كان الهدف من هذا الفصل هو إظهار أن الأولاد والبنات السيئين فقط يكتبون تعليمات برمجية موجهة للكائنات في Rust: هنا Optionتحتاج إلى نسخ ولصق كل من عمليات التنفيذ غير الضرورية والتافهة للطريقة في جميع تطبيقات السمة. ولكن إذا قمت بتطبيق حيلتين ، فستختفي اللوحة المعيارية بأكملها وستزيد سهولة القراءة.
مقياس العمل
نصت المقالة الأصلية على نموذج لسير عمل منشور مدونة. دعنا نظهر خيالنا ونكيف الوصف الأصلي للواقع الروسي القاسي:
- كانت أي مقالة عن حبري مسودة فارغة ، وكان على المؤلف أن يملأها بالمحتوى.
- عندما تكون المقالة جاهزة ، يتم إرسالها للمراجعة.
- بمجرد موافقة الوسيط على المقال ، يتم نشره في Habré.
- حتى يتم نشر المقال ، يجب ألا يرى المستخدمون محتواه.
يجب ألا يكون لأي إجراءات غير قانونية مع المقالة أي تأثير (على سبيل المثال ، لا يمكنك نشر مقال غير معتمد من وضع الحماية).
توضح القائمة أدناه الرمز المقابل للوصف أعلاه.
// main.rs
use article::Article;
mod article;
fn main() {
let mut article = Article::empty();
article.add_text("Rust -");
assert_eq!(None, article.content());
article.send_to_moderators();
assert_eq!(None, article.content());
article.publish();
assert_eq!(Some("Rust -"), article.content());
}
Article حتى الآن يبدو مثل هذا:
// article/mod.rs
pub struct Article;
impl Article {
pub fn empty() -> Self {
Self
}
pub fn add_text(&self, _text: &str) {
// no-op
}
pub fn content(&self) -> Option<&str> {
None
}
pub fn send_to_moderators(&self) {
// no-op
}
pub fn publish(&self) {
// no-op
}
}
هذا يمر عبر جميع التأكيدات باستثناء آخر واحد. ليس سيئا!
تنفيذ النمط
دعنا نضيف سمة فارغة Stateوحالة Draftواثنين من الحقول إلى Article:
// article/state.rs
pub trait State {
// empty
}
// article/states.rs
use super::state::State;
pub struct Draft;
impl State for Draft {
// nothing
}
// article/mod.rs
use state::State;
use states::Draft;
mod state;
mod states;
pub struct Article {
state: Box<dyn State>,
content: String,
}
impl Article {
pub fn empty() -> Self {
Self {
state: Box::new(Draft),
content: String::new(),
}
}
// ...
}
مشاكل مع ابتعد التصميم
State, . , - :
trait State {
fn send_to_moderators(&mut self) -> &dyn State;
}
, , , — .
?
pub trait State {
fn send_to_moderators(&mut self) -> Box<dyn State>;
}
. . , ?
:
pub trait State {
fn send_to_moderators(self: Box<Self>) -> Box<dyn State>;
}
: ( self). , Self: Sized, .. . trait object, .. .
: , , , . , , ; , .
use crate::article::Article;
pub trait State {
fn send_to_moderators(&mut self) -> Transit {
Transit(None)
}
}
pub struct Transit(pub Option<Box<dyn State>>);
impl Transit {
pub fn to(state: impl State + 'static) -> Self {
Self(Some(Box::new(state)))
}
pub fn apply(self, article: &mut Article) -> Option<()> {
article.state = self.0?;
Some(())
}
}
, , Draft:
// article/states.rs
use super::state::{State, Transit};
pub struct Draft;
impl State for Draft {
fn send_to_moderators(&mut self) -> Transit {
Transit::to(PendingReview)
}
}
pub struct PendingReview;
impl State for PendingReview {
// nothing
}
// article/mod.rs
impl Article {
// ...
pub fn send_to_moderators(&mut self) {
self.state.send_to_moderators().apply(self);
}
// ...
}
-
: Published, State, publish PendingReview. Article::publish :)
. content State, Published , , Article:
// article/mod.rs
impl Article {
// ...
pub fn content(&self) -> Option<&str> {
self.state.content(self)
}
// ...
}
// article/state.rs
pub trait State {
// ...
fn content<'a>(&self, _article: &'a Article) -> Option<&'a str> {
None
}
}
// article/states.rs
impl State for Published {
fn content<'a>(&self, article: &'a Article) -> Option<&'a str> {
Some(&article.content)
}
}
, ? , !
impl Article {
// ...
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
// ...
}
( ) , .
! !
, Article , - , , . ? , ! .
, - Rust , , . - -.
, , Rust . , Observer: , Arc<Mutex<...>>!
, .