模式的力量
在软件开发中,模式是解决常见问题的可重用解决方案。Rust作为一门现代系统编程语言,不仅提供了强劲的类型系统和内存安全保证,还支持多种高级编程模式。掌握这些模式不仅能让我们写出更优雅的代码,还能提高代码的可维护性和可扩展性。
建造者模式
建造者模式在Rust中超级常见,特别是在配置复杂对象时:
#[derive(Debug, Clone)]
pub struct DatabaseConfig {
pub host: String,
pub port: u16,
pub username: String,
pub password: String,
pub database: String,
pub max_connections: u32,
pub timeout: std::time::Duration,
pub ssl: bool,
}
impl DatabaseConfig {
pub fn new() -> DatabaseConfigBuilder {
DatabaseConfigBuilder::default()
}
}
#[derive(Default)]
pub struct DatabaseConfigBuilder {
host: Option<String>,
port: Option<u16>,
username: Option<String>,
password: Option<String>,
database: Option<String>,
max_connections: Option<u32>,
timeout: Option<std::time::Duration>,
ssl: Option<bool>,
}
impl DatabaseConfigBuilder {
pub fn host(mut self, host: impl Into<String>) -> Self {
self.host = Some(host.into());
self
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn username(mut self, username: impl Into<String>) -> Self {
self.username = Some(username.into());
self
}
pub fn password(mut self, password: impl Into<String>) -> Self {
self.password = Some(password.into());
self
}
pub fn database(mut self, database: impl Into<String>) -> Self {
self.database = Some(database.into());
self
}
pub fn max_connections(mut self, max_connections: u32) -> Self {
self.max_connections = Some(max_connections);
self
}
pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
self.timeout = Some(timeout);
self
}
pub fn ssl(mut self, ssl: bool) -> Self {
self.ssl = Some(ssl);
self
}
pub fn build(self) -> Result<DatabaseConfig, String> {
Ok(DatabaseConfig {
host: self.host.ok_or("Host is required")?,
port: self.port.ok_or("Port is required")?,
username: self.username.ok_or("Username is required")?,
password: self.password.ok_or("Password is required")?,
database: self.database.ok_or("Database is required")?,
max_connections: self.max_connections.unwrap_or(10),
timeout: self.timeout.unwrap_or_else(|| std::time::Duration::from_secs(30)),
ssl: self.ssl.unwrap_or(false),
})
}
}
// 使用示例
fn main() -> Result<(), String> {
let config = DatabaseConfig::new()
.host("localhost")
.port(5432)
.username("user")
.password("password")
.database("mydb")
.max_connections(20)
.timeout(std::time::Duration::from_secs(60))
.ssl(true)
.build()?;
println!("Database config: {:?}", config);
Ok(())
}
策略模式
策略模式允许在运行时选择算法:
pub trait PaymentStrategy {
fn pay(&self, amount: f64) -> Result<(), PaymentError>;
}
#[derive(Debug)]
pub enum PaymentError {
InsufficientFunds,
NetworkError,
InvalidCard,
}
pub struct CreditCardPayment {
card_number: String,
cvv: String,
}
impl CreditCardPayment {
pub fn new(card_number: String, cvv: String) -> Self {
Self { card_number, cvv }
}
}
impl PaymentStrategy for CreditCardPayment {
fn pay(&self, amount: f64) -> Result<(), PaymentError> {
println!("Processing credit card payment of ${:.2}", amount);
// 模拟支付处理
if amount > 1000.0 {
Err(PaymentError::InsufficientFunds)
} else {
Ok(())
}
}
}
pub struct PayPalPayment {
email: String,
}
impl PayPalPayment {
pub fn new(email: String) -> Self {
Self { email }
}
}
impl PaymentStrategy for PayPalPayment {
fn pay(&self, amount: f64) -> Result<(), PaymentError> {
println!("Processing PayPal payment of ${:.2} to {}", amount, self.email);
// 模拟支付处理
Ok(())
}
}
pub struct BankTransferPayment {
account_number: String,
routing_number: String,
}
impl BankTransferPayment {
pub fn new(account_number: String, routing_number: String) -> Self {
Self { account_number, routing_number }
}
}
impl PaymentStrategy for BankTransferPayment {
fn pay(&self, amount: f64) -> Result<(), PaymentError> {
println!("Processing bank transfer of ${:.2}", amount);
// 模拟支付处理
Ok(())
}
}
pub struct PaymentProcessor {
strategy: Box<dyn PaymentStrategy>,
}
impl PaymentProcessor {
pub fn new(strategy: Box<dyn PaymentStrategy>) -> Self {
Self { strategy }
}
pub fn set_strategy(&mut self, strategy: Box<dyn PaymentStrategy>) {
self.strategy = strategy;
}
pub fn process_payment(&self, amount: f64) -> Result<(), PaymentError> {
self.strategy.pay(amount)
}
}
// 使用示例
fn main() -> Result<(), PaymentError> {
let credit_card = CreditCardPayment::new("1234-5678-9012-3456".to_string(), "123".to_string());
let mut processor = PaymentProcessor::new(Box::new(credit_card));
processor.process_payment(100.0)?;
let paypal = PayPalPayment::new("user@example.com".to_string());
processor.set_strategy(Box::new(paypal));
processor.process_payment(200.0)?;
Ok(())
}
观察者模式
观察者模式在Rust中可以通过trait和智能指针实现:
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
pub trait Observer {
fn update(&self, event: &Event);
}
#[derive(Debug, Clone)]
pub struct Event {
pub event_type: String,
pub data: String,
pub timestamp: std::time::SystemTime,
}
impl Event {
pub fn new(event_type: String, data: String) -> Self {
Self {
event_type,
data,
timestamp: std::time::SystemTime::now(),
}
}
}
pub struct EventBus {
observers: Arc<Mutex<HashMap<String, Vec<Arc<dyn Observer + Send + Sync>>>>>,
}
impl EventBus {
pub fn new() -> Self {
Self {
observers: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn subscribe(&self, event_type: String, observer: Arc<dyn Observer + Send + Sync>) {
let mut observers = self.observers.lock().unwrap();
observers.entry(event_type).or_insert_with(Vec::new).push(observer);
}
pub fn publish(&self, event: Event) {
let observers = self.observers.lock().unwrap();
if let Some(observers_list) = observers.get(&event.event_type) {
for observer in observers_list {
observer.update(&event);
}
}
}
}
// 具体的观察者实现
pub struct LogObserver {
name: String,
}
impl LogObserver {
pub fn new(name: String) -> Self {
Self { name }
}
}
impl Observer for LogObserver {
fn update(&self, event: &Event) {
println!("[{}] Event received: {:?}", self.name, event);
}
}
pub struct EmailObserver {
email: String,
}
impl EmailObserver {
pub fn new(email: String) -> Self {
Self { email }
}
}
impl Observer for EmailObserver {
fn update(&self, event: &Event) {
println!("Sending email to {}: Event '{}' occurred", self.email, event.event_type);
}
}
// 使用示例
fn main() {
let event_bus = EventBus::new();
let log_observer = Arc::new(LogObserver::new("Logger".to_string()));
let email_observer = Arc::new(EmailObserver::new("admin@example.com".to_string()));
event_bus.subscribe("user.login".to_string(), log_observer.clone());
event_bus.subscribe("user.login".to_string(), email_observer.clone());
event_bus.subscribe("user.logout".to_string(), log_observer.clone());
// 发布事件
event_bus.publish(Event::new("user.login".to_string(), "User 123 logged in".to_string()));
event_bus.publish(Event::new("user.logout".to_string(), "User 123 logged out".to_string()));
}
工厂模式
工厂模式在Rust中可以通过trait和枚举实现:
pub trait Animal {
fn make_sound(&self);
fn get_name(&self) -> &str;
}
pub struct Dog {
name: String,
}
impl Dog {
pub fn new(name: String) -> Self {
Self { name }
}
}
impl Animal for Dog {
fn make_sound(&self) {
println!("{} says: Woof!", self.name);
}
fn get_name(&self) -> &str {
&self.name
}
}
pub struct Cat {
name: String,
}
impl Cat {
pub fn new(name: String) -> Self {
Self { name }
}
}
impl Animal for Cat {
fn make_sound(&self) {
println!("{} says: Meow!", self.name);
}
fn get_name(&self) -> &str {
&self.name
}
}
pub struct Bird {
name: String,
}
impl Bird {
pub fn new(name: String) -> Self {
Self { name }
}
}
impl Animal for Bird {
fn make_sound(&self) {
println!("{} says: Tweet!", self.name);
}
fn get_name(&self) -> &str {
&self.name
}
}
#[derive(Debug)]
pub enum AnimalType {
Dog,
Cat,
Bird,
}
pub struct AnimalFactory;
impl AnimalFactory {
pub fn create_animal(animal_type: AnimalType, name: String) -> Box<dyn Animal> {
match animal_type {
AnimalType::Dog => Box::new(Dog::new(name)),
AnimalType::Cat => Box::new(Cat::new(name)),
AnimalType::Bird => Box::new(Bird::new(name)),
}
}
}
// 使用示例
fn main() {
let animals = vec![
AnimalFactory::create_animal(AnimalType::Dog, "Buddy".to_string()),
AnimalFactory::create_animal(AnimalType::Cat, "Whiskers".to_string()),
AnimalFactory::create_animal(AnimalType::Bird, "Tweety".to_string()),
];
for animal in animals {
println!("Animal: {}", animal.get_name());
animal.make_sound();
}
}
单例模式
在Rust中实现单例模式需要小心处理:
use std::sync::{Arc, Mutex, Once};
use std::sync::atomic::{AtomicPtr, Ordering};
pub struct DatabaseConnection {
connection_string: String,
}
impl DatabaseConnection {
fn new(connection_string: String) -> Self {
println!("Creating new database connection to: {}", connection_string);
Self { connection_string }
}
pub fn execute_query(&self, query: &str) {
println!("Executing query '{}' on connection to: {}", query, self.connection_string);
}
}
// 使用Once和AtomicPtr实现线程安全的单例
pub struct DatabaseManager {
connection: AtomicPtr<DatabaseConnection>,
init: Once,
}
impl DatabaseManager {
const fn new() -> Self {
Self {
connection: AtomicPtr::new(std::ptr::null_mut()),
init: Once::new(),
}
}
pub fn get_instance() -> &'static DatabaseManager {
static INSTANCE: DatabaseManager = DatabaseManager::new();
&INSTANCE
}
pub fn get_connection(&self) -> &DatabaseConnection {
self.init.call_once(|| {
let connection = Box::new(DatabaseConnection::new(
"postgresql://localhost/mydb".to_string()
));
self.connection.store(Box::into_raw(connection), Ordering::SeqCst);
});
unsafe {
&*self.connection.load(Ordering::SeqCst)
}
}
}
// 使用示例
fn main() {
let db_manager = DatabaseManager::get_instance();
// 多次调用返回同一个实例
let connection1 = db_manager.get_connection();
let connection2 = db_manager.get_connection();
connection1.execute_query("SELECT * FROM users");
connection2.execute_query("SELECT * FROM posts");
// 验证是同一个实例
println!("Same instance: {}", std::ptr::eq(connection1, connection2));
}
装饰器模式
装饰器模式在Rust中可以通过trait和组合实现:
pub trait Coffee {
fn cost(&self) -> f64;
fn description(&self) -> String;
}
pub struct SimpleCoffee;
impl Coffee for SimpleCoffee {
fn cost(&self) -> f64 {
2.0
}
fn description(&self) -> String {
"Simple coffee".to_string()
}
}
pub struct CoffeeDecorator {
coffee: Box<dyn Coffee>,
}
impl CoffeeDecorator {
pub fn new(coffee: Box<dyn Coffee>) -> Self {
Self { coffee }
}
}
impl Coffee for CoffeeDecorator {
fn cost(&self) -> f64 {
self.coffee.cost()
}
fn description(&self) -> String {
self.coffee.description()
}
}
pub struct MilkDecorator {
coffee: Box<dyn Coffee>,
}
impl MilkDecorator {
pub fn new(coffee: Box<dyn Coffee>) -> Self {
Self { coffee }
}
}
impl Coffee for MilkDecorator {
fn cost(&self) -> f64 {
self.coffee.cost() + 0.5
}
fn description(&self) -> String {
format!("{}, milk", self.coffee.description())
}
}
pub struct SugarDecorator {
coffee: Box<dyn Coffee>,
}
impl SugarDecorator {
pub fn new(coffee: Box<dyn Coffee>) -> Self {
Self { coffee }
}
}
impl Coffee for SugarDecorator {
fn cost(&self) -> f64 {
self.coffee.cost() + 0.2
}
fn description(&self) -> String {
format!("{}, sugar", self.coffee.description())
}
}
pub struct WhipDecorator {
coffee: Box<dyn Coffee>,
}
impl WhipDecorator {
pub fn new(coffee: Box<dyn Coffee>) -> Self {
Self { coffee }
}
}
impl Coffee for WhipDecorator {
fn cost(&self) -> f64 {
self.coffee.cost() + 0.8
}
fn description(&self) -> String {
format!("{}, whip", self.coffee.description())
}
}
// 使用示例
fn main() {
let coffee = Box::new(SimpleCoffee);
let coffee_with_milk = Box::new(MilkDecorator::new(coffee));
let coffee_with_milk_and_sugar = Box::new(SugarDecorator::new(coffee_with_milk));
let coffee_with_milk_sugar_and_whip = Box::new(WhipDecorator::new(coffee_with_milk_and_sugar));
println!("Description: {}", coffee_with_milk_sugar_and_whip.description());
println!("Cost: ${:.2}", coffee_with_milk_sugar_and_whip.cost());
}
命令模式
命令模式在Rust中可以通过trait实现:
pub trait Command {
fn execute(&self);
fn undo(&self);
}
pub struct Light {
is_on: bool,
}
impl Light {
pub fn new() -> Self {
Self { is_on: false }
}
pub fn turn_on(&mut self) {
self.is_on = true;
println!("Light is on");
}
pub fn turn_off(&mut self) {
self.is_on = false;
println!("Light is off");
}
pub fn is_on(&self) -> bool {
self.is_on
}
}
pub struct LightOnCommand {
light: std::rc::Rc<std::cell::RefCell<Light>>,
}
impl LightOnCommand {
pub fn new(light: std::rc::Rc<std::cell::RefCell<Light>>) -> Self {
Self { light }
}
}
impl Command for LightOnCommand {
fn execute(&self) {
self.light.borrow_mut().turn_on();
}
fn undo(&self) {
self.light.borrow_mut().turn_off();
}
}
pub struct LightOffCommand {
light: std::rc::Rc<std::cell::RefCell<Light>>,
}
impl LightOffCommand {
pub fn new(light: std::rc::Rc<std::cell::RefCell<Light>>) -> Self {
Self { light }
}
}
impl Command for LightOffCommand {
fn execute(&self) {
self.light.borrow_mut().turn_off();
}
fn undo(&self) {
self.light.borrow_mut().turn_on();
}
}
pub struct RemoteControl {
commands: Vec<Box<dyn Command>>,
undo_command: Option<Box<dyn Command>>,
}
impl RemoteControl {
pub fn new() -> Self {
Self {
commands: Vec::new(),
undo_command: None,
}
}
pub fn set_command(&mut self, command: Box<dyn Command>) {
self.commands.push(command);
}
pub fn press_button(&mut self, slot: usize) {
if let Some(command) = self.commands.get(slot) {
command.execute();
// 保存命令用于撤销
// 注意:这里简化了实现,实际中需要克隆命令
}
}
pub fn press_undo(&mut self) {
if let Some(command) = &self.undo_command {
command.undo();
}
}
}
// 使用示例
fn main() {
let light = std::rc::Rc::new(std::cell::RefCell::new(Light::new()));
let mut remote = RemoteControl::new();
remote.set_command(Box::new(LightOnCommand::new(light.clone())));
remote.set_command(Box::new(LightOffCommand::new(light.clone())));
remote.press_button(0); // 开灯
remote.press_button(1); // 关灯
}
适配器模式
适配器模式在Rust中可以通过trait实现:
// 现有的接口
pub trait OldPrinter {
fn print_old_format(&self, text: &str);
}
pub struct LegacyPrinter;
impl OldPrinter for LegacyPrinter {
fn print_old_format(&self, text: &str) {
println!("[LEGACY] {}", text);
}
}
// 新的接口
pub trait NewPrinter {
fn print(&self, text: &str);
fn print_with_format(&self, text: &str, format: &str);
}
pub struct ModernPrinter;
impl NewPrinter for ModernPrinter {
fn print(&self, text: &str) {
println!("[MODERN] {}", text);
}
fn print_with_format(&self, text: &str, format: &str) {
println!("[MODERN] [{}] {}", format, text);
}
}
// 适配器
pub struct PrinterAdapter {
legacy_printer: LegacyPrinter,
}
impl PrinterAdapter {
pub fn new(legacy_printer: LegacyPrinter) -> Self {
Self { legacy_printer }
}
}
impl NewPrinter for PrinterAdapter {
fn print(&self, text: &str) {
self.legacy_printer.print_old_format(text);
}
fn print_with_format(&self, text: &str, format: &str) {
// 将新格式转换为旧格式
let formatted_text = format!("[{}] {}", format, text);
self.legacy_printer.print_old_format(&formatted_text);
}
}
// 使用示例
fn main() {
let modern_printer = ModernPrinter;
let legacy_printer = LegacyPrinter;
let adapter = PrinterAdapter::new(legacy_printer);
// 使用现代接口
modern_printer.print("Hello from modern printer");
modern_printer.print_with_format("Formatted text", "INFO");
// 使用适配器
adapter.print("Hello from legacy printer via adapter");
adapter.print_with_format("Formatted text", "WARNING");
}
写在最后
Rust中的高级模式提供了:
- 代码复用:通过模式避免重复代码
- 灵活性:运行时选择不同的实现
- 可维护性:清晰的代码结构和职责分离
- 可扩展性:易于添加新功能
- 类型安全:编译时检查模式实现的正确性
掌握这些模式不仅能让我们写出更优雅的Rust代码,还能提高代码的质量和可维护性。模式是软件工程中的重大工具,它们协助我们解决常见的设计问题,并提供了经过验证的解决方案。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...