4

Rust语言之GoF设计模式:Visitor访问者游客模式

 1 year ago
source link: https://www.jdon.com/62624
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Rust语言之GoF设计模式:Visitor访问者游客模式


Visitor允许您将“外部”操作添加到整个类层次结构中,而无需更改这些类的现有代码。

访问者另外一个定义是:封装了一种对异构对象集合进行操作的算法。它允许在同一数据上写入多个不同的算法,而无需修改数据(或其主要行为)。

访问者模式在您想将算法应用于异构数据的任何地方都很有用。如果数据是同质的 同类型的,您可以使用类似迭代器的模式。使用访问者对象(而不是函数方法)允许访问者是有状态的,从而在节点之间传递信息。

访问者模式的目标不仅仅是“允许在异构的数据上编写多个不同的算法” . 使用访问者模式的主要原因是允许动态双重调度。假设您有一对抽象的访问者和数据,并且您在编译时不知道数据和访问者的实际类型是什么,您可以说 data.accept(visitor) 并让魔法发生。这在任何 OO 语言中都是完全可行的
在Rust实现例如:

let d : Data = some of(Stmt, Name, Expr, ...);
let v : Visitor = some of(Interpreter, ...);

并通过 d.accept(v) 而不对任何地方的类型进行匹配。

trait Data {
    fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result;
}

trait Visitor {
    type Result;

    fn visit_stmt(&mut self, stmt: &Stmt) -> Self::Result;
    fn visit_name(&mut self, name: &Name) -> Self::Result;
    fn visit_expr(&mut self, expr: &Expr) -> Self::Result;
}

impl Data for Stmt {
    fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result {
        visitor.visit_stmt(self)
    }
}

impl Data for Name {
    fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result {
        visitor.visit_name(self)
    }
}

impl Data for Expr {
    fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result {
        visitor.visit_expr(self)
    }
}

impl Visitor for Interpreter {
    fn visit_stmt(&mut self, stmt: &Stmt) -> Self::Result { unimplemented!() }
    fn visit_name(&mut self, name: &Name) -> Self::Result { unimplemented!() }
    fn visit_expr(&mut self, expr: &Expr) -> Self::Result { unimplemented!() }
}

Serde以这种方式使用访问者将序列化/反序列化与数据格式分离。
serde 使用访问者模式对其中间表示进行编码。如果它使用模式匹配而不是访问者模式,则必须将其中间表示实例化为枚举,这会增加不必要的开销。

specialization 
上述代码可通过specialization 实现如下:

#![feature(specialization)]

pub trait Visitor<T> {
    fn visit(&mut self, t:&T);
}

pub trait Visitable: Sized {
    fn accept<T>(&self, t: &mut T) where T: Visitor<Self> {
        t.visit(self);
    }
}

struct Expr;
impl Visitable for Expr {}

struct Term;
impl Visitable for Term {}

struct Vis;

impl <T> Visitor<T> for Vis where T: Visitable{
    default fn visit(&mut self, _: &T) {
        unimplemented!();
    }
}

impl Visitor<Expr> for Vis {
    fn visit(&mut self, _: &Expr) {
        println!("Visiting an Expression");
    }
}

impl Visitor<Term> for Vis {
    fn visit(&mut self, _: &Term) {
        println!("Visiting a Term");
    }
}

fn main() {
    let mut v = Vis;
    Expr.accept(&mut v);
    Term.accept(&mut v);
}

函数式编程中”折叠fold“类似访问者模式,对数据集合中的每个项目运行算法以创建一个新项目,从而创建一个全新的集合。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK