Modèles de conception en Rust avec exemples de code

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

Design Patterns en Rust : Guide Pratique avec Exemples



Les design patterns sont des solutions éprouvées à des problèmes de développement typiques. En Rust, en raison de son système de propriété unique et de son modèle mémoire, l'implémentation des patterns classiques diffère souvent des langages avec ramasse-miettes. Dans cet article, nous aborderons trois patterns clés : Singleton, Builder et Strategy, adaptés aux spécificités de Rust.



1. Pattern Singleton en Rust : État Global Sans unsafe



Singleton garantit qu'une classe n'a qu'une seule instance et fournit un point d'accès global à celle-ci. En Rust, la crate once_cell ou le std::sync::OnceLock stable (depuis Rust 1.70) est idéal pour cela.



Implémentation avec OnceLock

use std::sync::OnceLock;

pub struct Logger { level: String,}

impl Logger { pub fn global() -> &'static Logger { static INSTANCE: OnceLock<Logger> = OnceLock::new(); INSTANCE.get_or_init(|| Logger { level: "info".to_string(), }) }

pub fn log(&self, msg: &str) { println!("[{}] {}", self.level, msg); }}

fn main() { let logger = Logger::global(); logger.log("Hello, Rust!"); // Logger::global() retournera la même instance}


Avantages : Sécurité (pas de unsafe), initialisation paresseuse, sécurité des threads. Inconvénient — l'état global complique les tests.



2. Pattern Builder : Construction d'Objets Complexes



Builder sépare la construction d'un objet complexe de sa représentation. En Rust, il est particulièrement utile pour les structures avec de nombreux champs optionnels.



Exemple : Configuration d'un Client HTTP

pub struct HttpClient {    url: String,    timeout: u64,    headers: Vec<(String, String)>,}

pub struct HttpClientBuilder { url: String, timeout: Option<u64>, headers: Vec<(String, String)>,}

impl HttpClientBuilder { pub fn new(url: &str) -> Self { HttpClientBuilder { url: url.to_string(), timeout: None, headers: vec![], } }

pub fn timeout(mut self, secs: u64) -> Self { self.timeout = Some(secs); self }

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

pub fn build(self) -> HttpClient { HttpClient { url: self.url, timeout: self.timeout.unwrap_or(30), headers: self.headers, } }}

fn main() { let client = HttpClientBuilder::new("https://api.example.com") .timeout(10) .header("Authorization", "Bearer token123") .build(); println!("URL du client : {}", client.url);}


Important : L'utilisation de self (pas &self) dans les méthodes du builder évite les clonages et rend l'API plus ergonomique.



3. Pattern Strategy : Algorithmes comme Stratégies Interchangeables



Strategy définit une famille d'algorithmes, encapsule chacun d'eux et les rend interchangeables. En Rust, cela est implémenté via les traits et le dispatch dynamique (Box<dyn Trait>).



Exemple : Système de Tri

trait SortStrategy {    fn sort(&self, data: &mut [i32]);}

struct BubbleSort;impl SortStrategy for BubbleSort { fn sort(&self, data: &mut [i32]) { let n = data.len(); for i in 0..n { for j in 0..n - i - 1 { if data[j] > data[j + 1] { data.swap(j, j + 1); } } } }}

struct QuickSort;impl SortStrategy for QuickSort { fn sort(&self, da

Blogs

Book Recommendations