main.rs (1557B)
1 use std::collections::HashMap; 2 3 use structural_patterns::{ 4 BinaryOperation, CachingExpression, ConsoleLogger, Expression, LoggingExpression, 5 NumberExpression, Operator, TimingExpression, 6 }; 7 8 fn main() -> Result<(), String> { 9 /// Structural Patterns 10 /// 11 /// 1. Decorator Pattern 12 let expr = Box::new(NumberExpression::new(42.0)); 13 let cached = Box::new(CachingExpression::new(expr)); 14 let timed = Box::new(TimingExpression::new(cached)); 15 let logged = LoggingExpression::new(timed, Box::new(ConsoleLogger)); 16 // When evaluate is called on the outermost decorator, the call flows through 17 // each layer. The order of wrapping matters. 18 let result = logged.evaluate(&HashMap::new()); 19 20 /// 2. Composite Pattern 21 /// Because all nodes implement Expression, Decorator Pattern work seamlessly 22 /// with Composite Pattern trees. 23 /// The tree structure encodes operator precedence directly: 24 let multiply = Box::new(BinaryOperation::new( 25 Box::new(NumberExpression::new(3.0)), 26 Box::new(NumberExpression::new(4.0)), 27 Operator::Multiply, 28 )); 29 let add = Box::new(BinaryOperation::new( 30 Box::new(NumberExpression::new(2.0)), 31 multiply, 32 Operator::Add, 33 )); 34 /// Evaluating the tree is a single method call: 35 let variables = HashMap::new(); 36 println!("Expression: {}", add.to_string()); 37 match add.evaluate(&variables) { 38 Ok(result) => println!("Result: {}", result), 39 Err(error) => eprintln!("Error: {}", error), 40 } 41 42 Ok(()) 43 }