أنماط التصميم في Rust: المستوى المتقدم مع أمثلة
\n\nأنماط التصميم هي حلول مجربة للمشكلات النمطية تساعد في إنشاء بنية مرنة وقابلة للصيانة والتوسع. في Rust، مع نظام الملكية والاقتراض والسمات، تكتسب العديد من الأنماط الكلاسيكية تنفيذاً فريداً. في هذه المقالة، سنحلل أنماط التصميم المتقدمة التي تكون فعالة بشكل خاص في نظام Rust البيئي.
\n\n1. نمط Builder المتقدم (البناء)
\n\nغالباً ما يتم تنفيذ نمط Builder الكلاسيكي في Rust من خلال سلسلة من الدوال التي تعيد &mut Self. ومع ذلك، على المستوى المتقدم، نستخدم Builder المُنمّط مع أنواع الحالات لضمان الصحة في مرحلة التجميع.
المشكلة: التحكم في الحقول الإلزامية
\nلا يضمن Builder العادي أن المستخدم قد ملأ جميع الحقول الإلزامية. قد ننسى استدعاء .build() أو عدم تعيين معلمة بالغة الأهمية.
الحل: Builder مع أنواع وهمية
\nuse std::marker::PhantomData;\n\n// أنواع الحالات للحقول\nstruct UsernameNotSet;\nstruct UsernameSet;\nstruct PasswordNotSet;\nstruct PasswordSet;\n\nstruct UserBuilder<U, P> {\n username: Option<String>,\n password: Option<String>,\n _username: PhantomData<U>,\n _password: PhantomData<P>,\n}\n\nimpl UserBuilder<UsernameNotSet, PasswordNotSet> {\n pub fn new() -> Self {\n Self {\n username: None,\n password: None,\n _username: PhantomData,\n _password: PhantomData,\n }\n }\n}\n\nimpl<P> UserBuilder<UsernameNotSet, P> {\n pub fn username(mut self, name: &str) -> UserBuilder<UsernameSet, P> {\n self.username = Some(name.to_string());\n UserBuilder {\n username: self.username,\n password: self.password,\n _username: PhantomData,\n _password: PhantomData,\n }\n }\n}\n\nimpl<U> UserBuilder<U, PasswordNotSet> {\n pub fn password(mut self, pwd: &str) -> UserBuilder<U, PasswordSet> {\n self.password = Some(pwd.to_string());\n UserBuilder {\n username: self.username,\n password: self.password,\n _username: PhantomData,\n _password: PhantomData,\n }\n }\n}\n\nimpl UserBuilder<UsernameSet, PasswordSet> {\n pub fn build(self) -> User {\n User {\n username: self.username.expect("Username must be set"),\n password: self.password.expect("Password must be set"),\n }\n }\n}\n\npub struct User {\n pub username: String,\n pub password: String,\n}\n\nfn main() {\n // الآن لن يسمح المترجم باستدعاء build() دون تعيين كلا الحقلين\n let user = UserBuilder::new()\n .username("alice")\n .password("secret123")\n .build();\n println!("User: {}", user.username);\n}\n\nالميزة: يتم اكتشاف خطأ "نسيان الحقل" في مرحلة التجميع، وليس في وقت التشغيل.
\n\n2. نمط State (الحالة) عبر السمات
\n\nيسمح نمط State للكائن بتغيير سلوكه عند تغيير حالته الداخلية. في Rust، يتم تنفيذ ذلك بأناقة عبر التعدادات (enum) والسمات.
\n\nالتنفيذ باستخدام enum
\nenum ConnectionState {\n Disconnected,\n Connecting,\n Connected,\n}\n\nstruct Connection {\n state: ConnectionState,\n}\n\nimpl Connection {\n pub fn new() -> Self {\n Self { state: ConnectionState::Disconnected }\n }\n\n pub fn connect(&mut self) {\n match self.state {\n ConnectionState::Disconnected => {\n println!("بدء الاتصال...");\n self.state = ConnectionState::Connecting;\n }\n ConnectionState::Connecting => {\n printl