装饰器模式 Decorator
通过将对象包装在内部, 来动态地更改对象在运行时的行为.
一些现代化的编程语言, 例如 Python, 有提供这样的语言特定, 比如在执行函数之前以及运行完成之后, 都打印出日志, 这样的需求就可以用装饰器模式来实现. 比如下面的例子:
# 定义一个装饰器
def log_decorator(func):
# inner1 是一个包装函数
def inner1():
print("> before function execution")
# 调用真正的函数
func()
print("> after function execution")
return inner1
# 定义一个测试用的函数, 并应有上面定义好的装饰器; `@log_decorator` 等同于下面一行代码的写法:
# say_hello = log_decorator(say_hello)
@log_decorator
def hello():
print("hello()")
# 调用函数
say_hello()
问题描述
代码示例
#![deny(
warnings,
clippy::all,
clippy::cargo,
clippy::nursery,
clippy::pedantic
)]
pub trait Coffee {
fn get_cost(&self) -> f64;
fn get_description(&self) -> String;
}
pub struct SimpleCoffee {}
impl Default for SimpleCoffee {
fn default() -> Self {
Self::new()
}
}
impl SimpleCoffee {
#[must_use]
pub const fn new() -> Self {
Self {}
}
}
impl Coffee for SimpleCoffee {
fn get_cost(&self) -> f64 {
10.0
}
fn get_description(&self) -> String {
"Simple coffee".to_owned()
}
}
pub struct MilkCoffee {
inner: Box<dyn Coffee>,
}
impl MilkCoffee {
#[must_use]
pub const fn new(inner: Box<dyn Coffee>) -> Self {
Self { inner }
}
}
impl Coffee for MilkCoffee {
fn get_cost(&self) -> f64 {
self.inner.get_cost() + 2.0
}
fn get_description(&self) -> String {
let mut desc = self.inner.get_description();
desc.push_str(", milk");
desc
}
}
pub struct WilpCoffee {
inner: Box<dyn Coffee>,
}
impl WilpCoffee {
#[must_use]
pub const fn new(inner: Box<dyn Coffee>) -> Self {
Self { inner }
}
}
impl Coffee for WilpCoffee {
fn get_cost(&self) -> f64 {
self.inner.get_cost() + 5.0
}
fn get_description(&self) -> String {
let mut desc = self.inner.get_description();
desc.push_str(", wilp");
desc
}
}
pub struct VanillaCoffee {
inner: Box<dyn Coffee>,
}
impl VanillaCoffee {
#[must_use]
pub const fn new(inner: Box<dyn Coffee>) -> Self {
Self { inner }
}
}
impl Coffee for VanillaCoffee {
fn get_cost(&self) -> f64 {
self.inner.get_cost() + 3.0
}
fn get_description(&self) -> String {
let mut desc = self.inner.get_description();
desc.push_str(", vanilla");
desc
}
}
fn main() {
let coffee = Box::new(SimpleCoffee::new());
println!("cost: {}", coffee.get_cost());
println!("desc: {}", coffee.get_description());
let coffee = Box::new(MilkCoffee::new(coffee));
println!("cost: {}", coffee.get_cost());
println!("desc: {}", coffee.get_description());
let coffee = Box::new(WilpCoffee::new(coffee));
println!("cost: {}", coffee.get_cost());
println!("desc: {}", coffee.get_description());
let coffee = VanillaCoffee::new(coffee);
println!("cost: {}", coffee.get_cost());
println!("desc: {}", coffee.get_description());
}