الصدأ مقابل. حالة

هام : لقراءة المقال بشكل مريح ، يجب أن تكون قادرًا على قراءة الكود المصدري بلغة Rust وفهم سبب Rc<RefCell<...>>سوء تغليف كل شيء .



المقدمة



لا يعتبر الصدأ بشكل عام لغة كائنية التوجه: لا يوجد وراثة تنفيذية ؛ للوهلة الأولى ، لا يوجد تغليف أيضًا ؛ وأخيرا، الرسوم البيانية التبعية للكائنات قابلة للتغيير مألوفة جدا لOOP-الأتباع تبدو كما القبيح ممكن (مجرد إلقاء نظرة على كل هذه Rc<RefCell<...>>و Arc<Mutex<...>>!)



صحيح ، لقد تم اعتبار وراثة التنفيذ ضارة لعدة سنوات بالفعل ، ويقول معلمو OOP أشياء صحيحة جدًا مثل "الكائن الجيد هو كائن غير قابل للتغيير". لذلك كنت أتساءل: كيف جيدا هل التفكير كائن والصدأ حقا تناسب معا ؟



سيكون أول خنزير غينيا هو نمط الحالة ، والتنفيذ الخالص له هو موضوع هذه المقالة.



تم اختياره لسبب: فصل من The Rust Book مخصص لنفس النمط . كان الهدف من هذا الفصل هو إظهار أن الأولاد والبنات السيئين فقط يكتبون تعليمات برمجية موجهة للكائنات في Rust: هنا Optionتحتاج إلى نسخ ولصق كل من عمليات التنفيذ غير الضرورية والتافهة للطريقة في جميع تطبيقات السمة. ولكن إذا قمت بتطبيق حيلتين ، فستختفي اللوحة المعيارية بأكملها وستزيد سهولة القراءة.



مقياس العمل



نصت المقالة الأصلية على نموذج لسير عمل منشور مدونة. دعنا نظهر خيالنا ونكيف الوصف الأصلي للواقع الروسي القاسي:



  1. كانت أي مقالة عن حبري مسودة فارغة ، وكان على المؤلف أن يملأها بالمحتوى.
  2. عندما تكون المقالة جاهزة ، يتم إرسالها للمراجعة.
  3. بمجرد موافقة الوسيط على المقال ، يتم نشره في Habré.
  4. حتى يتم نشر المقال ، يجب ألا يرى المستخدمون محتواه.


يجب ألا يكون لأي إجراءات غير قانونية مع المقالة أي تأثير (على سبيل المثال ، لا يمكنك نشر مقال غير معتمد من وضع الحماية).



توضح القائمة أدناه الرمز المقابل للوصف أعلاه.



// 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, .. .





: , , , . , , ; , .



P.S.: Amethyst.



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<...>>!



, .




All Articles