Fortgeschrittene Entwurfsmuster in Rust mit Codebeispielen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Entwurfsmuster in Rust: Fortgeschrittenes Niveau mit Beispielen

\n\n

Entwurfsmuster sind bewährte Lösungen für typische Aufgaben, die helfen, eine flexible, wartbare und skalierbare Architektur zu erstellen. In Rust, mit seinem System der Eigentümerschaft, Ausleihe und Traits, erhalten viele klassische Entwurfsmuster eine einzigartige Implementierung. In diesem Artikel werden wir fortgeschrittene Entwurfsmuster behandeln, die im Rust-Ökosystem besonders effektiv sind.

\n\n

1. Fortgeschrittener Builder

\n\n

Der klassische Builder-Pattern wird in Rust oft durch eine Methodenkette implementiert, die &mut Self zurückgibt. Auf fortgeschrittenem Niveau verwenden wir jedoch einen typisierten Builder mit Zustandstypen, um die Korrektheit bereits zur Kompilierzeit sicherzustellen.

\n\n

Problem: Kontrolle der Pflichtfelder

\n

Ein gewöhnlicher Builder garantiert nicht, dass der Benutzer alle Pflichtfelder ausgefüllt hat. Wir könnten vergessen, .build() aufzurufen oder einen kritischen Parameter nicht zu setzen.

\n\n

Lösung: Builder mit Phantom-Typen

\n
use std::marker::PhantomData;\n\n// Zustandstypen für Felder\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    // Jetzt verhindert der Compiler den Aufruf von build(), ohne beide Felder gesetzt zu haben\n    let user = UserBuilder::new()\n        .username("alice")\n        .password("secret123")\n        .build();\n    println!("User: {}", user.username);\n}
\n\n

Vorteil: Der Fehler "Feld vergessen" wird bereits zur Kompilierzeit erkannt, nicht erst zur Laufzeit.

\n\n

2. State-Pattern über Traits

\n\n

Das State-Pattern ermöglicht es einem Objekt, sein Verhalten bei Änderung des internen Zustands zu ändern. In Rust wird dies elegant durch Enumerationen (enum) und Traits implementiert.

\n\n

Implementierung mit enum

\n
enum 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!("Beginne Verbindung...");\n                self.state = ConnectionState::Connecting;\n            }\n            ConnectionState::Connecting => {\n                printl                

Blogs

Buchempfehlungen