// 30_design_patterns.ruchy - Common design patterns implementation
fn main() {
println("=== Design Patterns ===\n")
// Singleton Pattern
println("=== Singleton Pattern ===")
module Database {
let mut instance = None
pub fn get_instance() {
if instance == None {
instance = Some({
connection: "Connected to DB",
query: |sql| f"Executing: {sql}"
})
}
instance.unwrap()
}
}
let db1 = Database::get_instance()
let db2 = Database::get_instance()
println(f"Same instance: {db1 == db2}")
// Factory Pattern
println("\n=== Factory Pattern ===")
trait Animal {
fn speak(self)
}
struct Dog {
name: string
}
impl Animal for Dog {
fn speak(self) {
f"{self.name} says: Woof!"
}
}
struct Cat {
name: string
}
impl Animal for Cat {
fn speak(self) {
f"{self.name} says: Meow!"
}
}
fn animal_factory(type, name) {
match type {
"dog" => Dog { name: name },
"cat" => Cat { name: name },
_ => throw f"Unknown animal type: {type}"
}
}
let dog = animal_factory("dog", "Buddy")
let cat = animal_factory("cat", "Whiskers")
println(dog.speak())
println(cat.speak())
// Builder Pattern
println("\n=== Builder Pattern ===")
struct HttpRequestBuilder {
method: string = "GET",
url: string = "",
headers: map = {},
body: Option<string> = None,
timeout: int = 30000
}
impl HttpRequestBuilder {
fn new() {
HttpRequestBuilder {}
}
fn method(mut self, method) {
self.method = method
self
}
fn url(mut self, url) {
self.url = url
self
}
fn header(mut self, key, value) {
self.headers[key] = value
self
}
fn body(mut self, body) {
self.body = Some(body)
self
}
fn timeout(mut self, ms) {
self.timeout = ms
self
}
fn build(self) {
{
method: self.method,
url: self.url,
headers: self.headers,
body: self.body,
timeout: self.timeout
}
}
}
let request = HttpRequestBuilder::new()
.method("POST")
.url("https://api.example.com/users")
.header("Content-Type", "application/json")
.body('{"name": "John"}')
.timeout(5000)
.build()
println(f"Request: {request}")
// Observer Pattern
println("\n=== Observer Pattern ===")
struct Subject {
observers: list = [],
state: any = None
}
impl Subject {
fn attach(mut self, observer) {
self.observers.append(observer)
}
fn detach(mut self, observer) {
self.observers.remove(observer)
}
fn notify(self) {
for observer in self.observers {
observer.update(self.state)
}
}
fn set_state(mut self, state) {
self.state = state
self.notify()
}
}
struct Observer {
name: string,
update: fn(state)
}
let subject = Subject {}
let observer1 = Observer {
name: "Observer1",
update: |state| println(f"Observer1 received: {state}")
}
let observer2 = Observer {
name: "Observer2",
update: |state| println(f"Observer2 received: {state}")
}
subject.attach(observer1)
subject.attach(observer2)
subject.set_state("New State!")
// Strategy Pattern
println("\n=== Strategy Pattern ===")
trait SortStrategy {
fn sort(self, data)
}
struct BubbleSort {}
impl SortStrategy for BubbleSort {
fn sort(self, data) {
// Bubble sort implementation
println("Using bubble sort")
data.sorted()
}
}
struct QuickSort {}
impl SortStrategy for QuickSort {
fn sort(self, data) {
// Quick sort implementation
println("Using quick sort")
data.sorted()
}
}
struct Sorter {
strategy: SortStrategy
}
impl Sorter {
fn sort(self, data) {
self.strategy.sort(data)
}
fn set_strategy(mut self, strategy) {
self.strategy = strategy
}
}
let data = [3, 1, 4, 1, 5, 9, 2, 6]
let mut sorter = Sorter { strategy: BubbleSort {} }
sorter.sort(data)
sorter.set_strategy(QuickSort {})
sorter.sort(data)
// Decorator Pattern
println("\n=== Decorator Pattern ===")
trait Coffee {
fn cost(self) -> float
fn description(self) -> string
}
struct SimpleCoffee {}
impl Coffee for SimpleCoffee {
fn cost(self) { 2.0 }
fn description(self) { "Simple coffee" }
}
struct MilkDecorator {
coffee: Coffee
}
impl Coffee for MilkDecorator {
fn cost(self) {
self.coffee.cost() + 0.5
}
fn description(self) {
f"{self.coffee.description()} + milk"
}
}
struct SugarDecorator {
coffee: Coffee
}
impl Coffee for SugarDecorator {
fn cost(self) {
self.coffee.cost() + 0.2
}
fn description(self) {
f"{self.coffee.description()} + sugar"
}
}
let coffee = SimpleCoffee {}
let coffee_with_milk = MilkDecorator { coffee: coffee }
let fancy_coffee = SugarDecorator { coffee: coffee_with_milk }
println(f"{fancy_coffee.description()} costs ${fancy_coffee.cost()}")
// Chain of Responsibility
println("\n=== Chain of Responsibility ===")
trait Handler {
fn handle(self, request) -> Option<string>
}
struct AuthHandler {
next: Option<Handler>
}
impl Handler for AuthHandler {
fn handle(self, request) {
if !request.authenticated {
Some("Authentication required")
} else if self.next {
self.next.handle(request)
} else {
None
}
}
}
struct ValidationHandler {
next: Option<Handler>
}
impl Handler for ValidationHandler {
fn handle(self, request) {
if !request.valid {
Some("Invalid request")
} else if self.next {
self.next.handle(request)
} else {
None
}
}
}
// Command Pattern
println("\n=== Command Pattern ===")
trait Command {
fn execute(self)
fn undo(self)
}
struct Light {
is_on: bool = false
}
struct LightOnCommand {
light: Light
}
impl Command for LightOnCommand {
fn execute(self) {
self.light.is_on = true
println("Light turned on")
}
fn undo(self) {
self.light.is_on = false
println("Light turned off")
}
}
struct RemoteControl {
commands: list = [],
history: list = []
}
impl RemoteControl {
fn set_command(mut self, slot, command) {
self.commands[slot] = command
}
fn press_button(mut self, slot) {
if slot < self.commands.len() {
let command = self.commands[slot]
command.execute()
self.history.append(command)
}
}
fn undo(mut self) {
if self.history.len() > 0 {
let command = self.history.pop()
command.undo()
}
}
}
// Template Method Pattern
println("\n=== Template Method Pattern ===")
trait DataProcessor {
fn process(self, data) {
let validated = self.validate(data)
let transformed = self.transform(validated)
let result = self.save(transformed)
result
}
fn validate(self, data)
fn transform(self, data)
fn save(self, data)
}
struct CSVProcessor {}
impl DataProcessor for CSVProcessor {
fn validate(self, data) {
println("Validating CSV")
data
}
fn transform(self, data) {
println("Transforming CSV")
data
}
fn save(self, data) {
println("Saving CSV")
"CSV processed"
}
}
// Adapter Pattern
println("\n=== Adapter Pattern ===")
struct OldPrinter {
fn print_old_format(self, text) {
println(f"Old printer: {text}")
}
}
trait ModernPrinter {
fn print(self, document)
}
struct PrinterAdapter {
old_printer: OldPrinter
}
impl ModernPrinter for PrinterAdapter {
fn print(self, document) {
// Convert modern document to old format
let old_format = f"[LEGACY] {document.content}"
self.old_printer.print_old_format(old_format)
}
}
// Proxy Pattern
println("\n=== Proxy Pattern ===")
trait Image {
fn display(self)
}
struct RealImage {
filename: string
}
impl Image for RealImage {
fn display(self) {
println(f"Displaying {self.filename}")
}
}
struct ImageProxy {
filename: string,
real_image: Option<RealImage> = None
}
impl Image for ImageProxy {
fn display(mut self) {
if self.real_image == None {
println(f"Loading {self.filename}...")
self.real_image = Some(RealImage { filename: self.filename })
}
self.real_image.unwrap().display()
}
}
let image = ImageProxy { filename: "photo.jpg" }
image.display() // Loads and displays
image.display() // Just displays (already loaded)
}