Explore a detailed reference guide for Rust design patterns, including intent, structure, and usage with code examples and diagrams.
Welcome to the Design Pattern Reference Cheat Sheet for Rust! This section provides a concise overview of key design patterns, their intent, structure, and usage in Rust. Each pattern is accompanied by diagrams and code snippets to illustrate its application. Use this guide for quick consultation during development to enhance your Rust programming skills.
1struct Computer {
2 cpu: String,
3 ram: u32,
4 storage: u32,
5}
6
7struct ComputerBuilder {
8 cpu: String,
9 ram: u32,
10 storage: u32,
11}
12
13impl ComputerBuilder {
14 fn new() -> Self {
15 ComputerBuilder {
16 cpu: String::from(""),
17 ram: 0,
18 storage: 0,
19 }
20 }
21
22 fn cpu(mut self, cpu: &str) -> Self {
23 self.cpu = cpu.to_string();
24 self
25 }
26
27 fn ram(mut self, ram: u32) -> Self {
28 self.ram = ram;
29 self
30 }
31
32 fn storage(mut self, storage: u32) -> Self {
33 self.storage = storage;
34 self
35 }
36
37 fn build(self) -> Computer {
38 Computer {
39 cpu: self.cpu,
40 ram: self.ram,
41 storage: self.storage,
42 }
43 }
44}
45
46fn main() {
47 let computer = ComputerBuilder::new()
48 .cpu("Intel i7")
49 .ram(16)
50 .storage(512)
51 .build();
52}
1trait Product {
2 fn operation(&self) -> String;
3}
4
5struct ConcreteProductA;
6struct ConcreteProductB;
7
8impl Product for ConcreteProductA {
9 fn operation(&self) -> String {
10 "Result of ConcreteProductA".to_string()
11 }
12}
13
14impl Product for ConcreteProductB {
15 fn operation(&self) -> String {
16 "Result of ConcreteProductB".to_string()
17 }
18}
19
20trait Creator {
21 fn factory_method(&self) -> Box<dyn Product>;
22}
23
24struct ConcreteCreatorA;
25struct ConcreteCreatorB;
26
27impl Creator for ConcreteCreatorA {
28 fn factory_method(&self) -> Box<dyn Product> {
29 Box::new(ConcreteProductA)
30 }
31}
32
33impl Creator for ConcreteCreatorB {
34 fn factory_method(&self) -> Box<dyn Product> {
35 Box::new(ConcreteProductB)
36 }
37}
38
39fn main() {
40 let creator_a = ConcreteCreatorA;
41 let product_a = creator_a.factory_method();
42 println!("{}", product_a.operation());
43
44 let creator_b = ConcreteCreatorB;
45 let product_b = creator_b.factory_method();
46 println!("{}", product_b.operation());
47}
1trait Target {
2 fn request(&self) -> String;
3}
4
5struct Adaptee;
6
7impl Adaptee {
8 fn specific_request(&self) -> String {
9 "Specific request".to_string()
10 }
11}
12
13struct Adapter {
14 adaptee: Adaptee,
15}
16
17impl Target for Adapter {
18 fn request(&self) -> String {
19 self.adaptee.specific_request()
20 }
21}
22
23fn main() {
24 let adaptee = Adaptee;
25 let adapter = Adapter { adaptee };
26 println!("{}", adapter.request());
27}
1trait Component {
2 fn operation(&self) -> String;
3}
4
5struct Leaf;
6
7impl Component for Leaf {
8 fn operation(&self) -> String {
9 "Leaf".to_string()
10 }
11}
12
13struct Composite {
14 children: Vec<Box<dyn Component>>,
15}
16
17impl Composite {
18 fn new() -> Self {
19 Composite {
20 children: Vec::new(),
21 }
22 }
23
24 fn add(&mut self, component: Box<dyn Component>) {
25 self.children.push(component);
26 }
27}
28
29impl Component for Composite {
30 fn operation(&self) -> String {
31 let mut result = String::from("Composite(");
32 for child in &self.children {
33 result.push_str(&child.operation());
34 }
35 result.push(')');
36 result
37 }
38}
39
40fn main() {
41 let mut composite = Composite::new();
42 composite.add(Box::new(Leaf));
43 composite.add(Box::new(Leaf));
44 println!("{}", composite.operation());
45}
1trait Strategy {
2 fn execute(&self) -> String;
3}
4
5struct ConcreteStrategyA;
6struct ConcreteStrategyB;
7
8impl Strategy for ConcreteStrategyA {
9 fn execute(&self) -> String {
10 "Strategy A".to_string()
11 }
12}
13
14impl Strategy for ConcreteStrategyB {
15 fn execute(&self) -> String {
16 "Strategy B".to_string()
17 }
18}
19
20struct Context {
21 strategy: Box<dyn Strategy>,
22}
23
24impl Context {
25 fn new(strategy: Box<dyn Strategy>) -> Self {
26 Context { strategy }
27 }
28
29 fn execute_strategy(&self) -> String {
30 self.strategy.execute()
31 }
32}
33
34fn main() {
35 let context_a = Context::new(Box::new(ConcreteStrategyA));
36 println!("{}", context_a.execute_strategy());
37
38 let context_b = Context::new(Box::new(ConcreteStrategyB));
39 println!("{}", context_b.execute_strategy());
40}
1use std::cell::RefCell;
2use std::rc::Rc;
3
4trait Observer {
5 fn update(&self, state: &str);
6}
7
8struct ConcreteObserver {
9 name: String,
10}
11
12impl Observer for ConcreteObserver {
13 fn update(&self, state: &str) {
14 println!("{} received update: {}", self.name, state);
15 }
16}
17
18struct Subject {
19 observers: Vec<Rc<RefCell<dyn Observer>>>,
20 state: String,
21}
22
23impl Subject {
24 fn new() -> Self {
25 Subject {
26 observers: Vec::new(),
27 state: String::new(),
28 }
29 }
30
31 fn attach(&mut self, observer: Rc<RefCell<dyn Observer>>) {
32 self.observers.push(observer);
33 }
34
35 fn set_state(&mut self, state: String) {
36 self.state = state;
37 self.notify();
38 }
39
40 fn notify(&self) {
41 for observer in &self.observers {
42 observer.borrow().update(&self.state);
43 }
44 }
45}
46
47fn main() {
48 let observer1 = Rc::new(RefCell::new(ConcreteObserver {
49 name: "Observer 1".to_string(),
50 }));
51 let observer2 = Rc::new(RefCell::new(ConcreteObserver {
52 name: "Observer 2".to_string(),
53 }));
54
55 let mut subject = Subject::new();
56 subject.attach(observer1);
57 subject.attach(observer2);
58
59 subject.set_state("New State".to_string());
60}
Rc and RefCell for shared ownership and interior mutability. 1use std::sync::mpsc;
2use std::thread;
3
4enum Message {
5 Increment,
6 Decrement,
7 Print,
8}
9
10struct Actor {
11 count: i32,
12}
13
14impl Actor {
15 fn new() -> Self {
16 Actor { count: 0 }
17 }
18
19 fn handle_message(&mut self, message: Message) {
20 match message {
21 Message::Increment => self.count += 1,
22 Message::Decrement => self.count -= 1,
23 Message::Print => println!("Count: {}", self.count),
24 }
25 }
26}
27
28fn main() {
29 let (tx, rx) = mpsc::channel();
30 let mut actor = Actor::new();
31
32 let handle = thread::spawn(move || {
33 for message in rx {
34 actor.handle_message(message);
35 }
36 });
37
38 tx.send(Message::Increment).unwrap();
39 tx.send(Message::Increment).unwrap();
40 tx.send(Message::Print).unwrap();
41 tx.send(Message::Decrement).unwrap();
42 tx.send(Message::Print).unwrap();
43
44 handle.join().unwrap();
45}
1fn main() {
2 let result = Some(2)
3 .and_then(|x| Some(x + 3))
4 .and_then(|x| Some(x * 2));
5
6 match result {
7 Some(value) => println!("Result: {}", value),
8 None => println!("No result"),
9 }
10}
Option and Result types to implement monadic behavior.
classDiagram
class Component {
<<interface>>
+operation() String
}
class Leaf {
+operation() String
}
class Composite {
+operation() String
+add(component: Component)
}
Component <|-- Leaf
Component <|-- Composite
Composite o-- Component
Remember, this cheat sheet is just the beginning. As you progress, you’ll build more complex and interactive applications using these patterns. Keep experimenting, stay curious, and enjoy the journey!