Entwurfsmuster in Rust mit Beispielen: von A bis Z

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: von der Theorie zur Praxis



Entwurfsmuster sind bewährte Lösungen für typische Aufgaben in der Softwareentwicklung. In Rust erhalten viele klassische Muster durch das einzigartige Ownership-System und das Fehlen klassischer OOP eine neue Bedeutung. In diesem Artikel betrachten wir vier Schlüsselmuster: Singleton, Factory, Builder und Strategy, angepasst an idiomatisches Rust.



1. Singleton in Rust



In Rust gibt es keine globalen statischen Variablen im herkömmlichen Sinne. Singleton kann jedoch über lazy_static oder OnceCell implementiert werden. Betrachten wir ein Beispiel mit std::sync::OnceLock (verfügbar seit Rust 1.70).



Implementierung mit OnceLock



use std::sync::OnceLock;

static CONFIG: OnceLock<Config> = OnceLock::new();

#[derive(Debug)]struct Config { db_url: String, port: u16,}

fn get_config() -> &'static Config { CONFIG.get_or_init(|| { Config { db_url: String::from("postgres://localhost"), port: 5432, } })}

fn main() { let cfg = get_config(); println!("{:?}", cfg);}


Kernpunkt: OnceLock garantiert einmalige Initialisierung und Threadsicherheit. Dies ist ein idiomatischer Weg für Rust.



2. Factory über Traits



Das Factory-Muster lässt sich in Rust hervorragend mit Traits umsetzen. Wir brauchen keine abstrakten Klassen – es reicht, eine Schnittstelle über ein Trait zu definieren.



Beispiel: Erstellung von Transportmitteln



trait Transport {    fn deliver(&self);}

struct Truck;impl Transport for Truck { fn deliver(&self) { println!("Lieferung per LKW auf dem Landweg"); }}

struct Ship;impl Transport for Ship { fn deliver(&self) { println!("Lieferung per Schiff auf dem Seeweg"); }}

struct LogisticsFactory;

impl LogisticsFactory { fn create_transport(route_type: &str) -> Box<dyn Transport> { match route_type { "land" => Box::new(Truck), "sea" => Box::new(Ship), _ => panic!("Unbekannter Routentyp"), } }}

fn main() { let transport = LogisticsFactory::create_transport("sea"); transport.deliver();}


Vorteil: Rust benötigt keine Vererbung – Polymorphismus wird über Traits und Box<dyn Trait> erreicht.



3. Builder mit typisierter Methodenverkettung



Builder wird in Rust häufig verwendet, besonders für Strukturen mit vielen optionalen Parametern. Wir implementieren ihn mit einer typisierten Methodenverkettung, die &mut Self zurückgibt.



Beispiel: Erstellung einer HTTP-Anfrage



#[derive(Debug, Default)]struct HttpRequest {    url: String,    method: String,    headers: Vec<(String, String)>,    body: Option<String>,}

struct HttpRequestBuilder { request: HttpRequest,}

impl HttpRequestBuilder { fn new(url: &str) -> Self { HttpRequestBuilder { request: HttpRequest { url: url.to_string(), method: "GET".to_string(), ..Default::default() }, } }

fn method(&mut self, method: &str) -> &mut Self { self.request.method = method.to_string(); self }

fn header(&mut self, key: &str, value: &str) -> &mut Self { self.request.headers.push((key.to_string(), value.to_string())); self }

fn body(&mut self, body: &str) -> &mut Self { self.request.body = Some(body.to_string()); self }

fn build(&self) -> HttpRequest { // Hier kann Validierung hinzugefügt werden HttpRequest { ..self.request.clone() } }}

fn ma

Blogs

Buchempfehlungen