Modèles de conception en Rust avec exemples : de A à Z

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Modèles de conception en Rust : de la théorie à la pratique



Les modèles de conception sont des solutions éprouvées aux problèmes typiques du développement logiciel. En Rust, grâce à son système unique de possession (ownership) et à l'absence d'POO classique, de nombreux modèles classiques prennent une nouvelle dimension. Dans cet article, nous allons analyser quatre modèles clés : Singleton, Factory, Builder et Strategy, adaptés au Rust idiomatique.



1. Singleton en Rust



Rust n'a pas de variables statiques globales au sens habituel. Cependant, Singleton peut être implémenté via lazy_static ou OnceCell. Considérons un exemple avec std::sync::OnceLock (disponible depuis Rust 1.70).



Implémentation avec 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);}


Point clé : OnceLock garantit une initialisation unique et la sécurité des threads. C'est une manière idiomatique pour Rust.



2. Factory via les traits



Le modèle Factory en Rust s'implémente parfaitement à l'aide de traits. Nous n'avons pas besoin de classes abstraites — il suffit de définir une interface via un trait.



Exemple : création de véhicules



trait Transport {    fn deliver(&self);}

struct Truck;impl Transport for Truck { fn deliver(&self) { println!("Livraison par camion sur terre"); }}

struct Ship;impl Transport for Ship { fn deliver(&self) { println!("Livraison par bateau sur mer"); }}

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!("Type d'itinéraire inconnu"), } }}

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


Avantage : Rust n'exige pas d'héritage — le polymorphisme est atteint via les traits et Box<dyn Trait>.



3. Builder avec chaîne typée



Builder en Rust est utilisé partout, surtout pour les structures avec de nombreux paramètres optionnels. Implémentons-le avec une chaîne typée de méthodes retournant &mut Self.



Exemple : création d'une requête HTTP



#[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 { // Ici on peut ajouter une validation HttpRequest { ..self.request.clone() } }}

fn ma

Blogs

Book Recommendations