Rust语言之GoF设计模式:装饰器Decorator模式


装饰器又称为油漆工模式,是一种结构模式,在不改动原有结构和代码的情况下,增加新行为、新功能或新职责,就像在原来油漆基础上再刷新油漆。
也可以称为过滤器模式,当然,过滤器模式更接近于职责链模式,当过滤器很多,专门需要组成一个链条时,就成了职责链模式,但是如果只有几个过滤器,而这几个过滤器依附原有对象,是为原有对象添砖加瓦,以原有对象为主,那么还是装饰器模式。

Rust 的标准库中有一个用于输入/输出操作的实际示例。

BufferReader是在矢量阅读器基础上添加缓冲行为:

let mut input = BufReader::new(Cursor::new("Input data"));
input.read(&mut buf).ok();


Rust 中的派生宏是否类似于 Python 中的装饰器?
在 Python 中添加一个装饰器,该函数将获得增强的属性。在 Rust 中使用派生decorate 也是这个目的。

在python中,装饰器是一个返回函数的函数:

@decorate
def f():
    pass

这段代码等于:

def f():
    pass
f = decorate(f)

而在 Rust 中,派生宏可获取被装饰事物的文本,并且可以根据需要重写它。
它们的目的相似,但它们使用的机制却大不相同。
Rust派生宏仅用于类型;但在 Python 中,可以在函数上使用装饰器。

主要区别在于使用某种形式的全局状态;

  • Python 装饰器,由于只是一个经典的 Python 可调用对象,就可以保持一些内部状态;
  • 而派生宏是在特殊的编译过程中执行的,并且不同调用的顺序,甚至宏可能被调用的次数都不能保证。
    理想情况下,派生宏不应保持任何状态。
    这就是为什么提供派生宏的 crates 还提供其他东西来处理共享状态。

Rust“派生宏”与“属性宏”区别

  • #[derive(SomeName)]是一个只能应用于struct/enum/union类型定义的属性,然后它将SomeName派生宏(称为过程宏)应用于进行类型定义的源代码。然后宏可以输出/吐出/放出自己的伪造源代码,这种伪造源代码是在原始类型定义源旁边放出,而原始源代码是不受派生宏的影响。
  • #[some_name]是一个属性,可以应用于任何 Rust 项(以及将来,甚至是 Rust 表达式和语句(甚至可能是类型和模式)),包括函数。它将宏应用于进行项目定义some_name的源代码。这个输入的some_name源代码不会重新再被放出,因此属性宏具有决定放出什么的所有权力。

说白了,Rust的宏还在编译时起作用,而不是像其他语言Java或Python在运行时起作用,更接近于Decorator模式。