• 用Rust实现的访问者模式
  • 发布于 2个月前
  • 191 热度
    0 评论
  • 张蜚
  • 22 粉丝 35 篇博客
  •   
访问者模式介绍
访问者是一种设计模式,它允许向对象集合添加新操作,而不需要修改对象本身,这一点很重要。如果你想在Rust中实现Visitor模式,你可以使用trait来实现。首先我们来看一下基本结构:

1,在访问者界面中实现访问(visit)功能,这确保元素可以被访问。
2,在Element中实现接受(accept)功能。这确保当访问Element时,可以执行操作。


在Rust中的实现访问者模式
新建一个Rust项目:
cargo new rust_visitor
我们首先定义Visitor trait:
pub trait Visitor {
    fn visit_person(&self, person:&Person);
    fn visit_organization(&self, o:&Organization);
}
然后是Element trait:
pub trait Element {
    fn accept(&self, visitor: &mut dyn Visitor);
}
在我们的例子中,我们可以访问Person和Organization,我们将从Person开始:
pub struct Person {
    email: String,
    name: String,
}
// 堆代码 duidaima.com
impl Element for Person {
    fn accept(&self, visitor: &mut dyn Visitor) {
        visitor.visit_person(self);
    }
}

impl Person {
    fn new(name:&str, email:&str)->Self {
        Self {
            email: email.to_string(),
            name: name.to_string()
        }
    }
}
1,首先,我们为Person结构体实现Element特征。很明显,它所做的就是调用visit_person方法并将Person对象作为参数传递。
2,接下来是构造函数的实现。我使用&str来防止生命周期问题。注意,Self指的是实现类型。

现在看看Organization结构体的实现:
pub struct Organization { 
    name: String,
    address: String
}

impl Element for Organization {
    fn accept(&self, visitor: &mut dyn Visitor) {
        visitor.visit_organization(self);
    }
}

impl Organization {
    fn new(name: &str, address:&str)->Self {
        Self {
            name: name.to_string(),
            address: address.to_string()
        }
    }
}
访问者是client,我们将实现一个非常简单的例子:
struct EmailVisitor;

impl Visitor for EmailVisitor {
    fn visit_person(&self, p:&Person) {
        println!("Sending email to {} at {}",p.name,p.email);
    }

    fn visit_organization(&self, o:&Organization) {
        println!("Sending mail to {} at {}",o.name,o.address);
    }
}
在这个简化示例中,EmailVisitor定义为空结构体。

测试
fn main() {
    let mut elements:Vec<Box<dyn Element>>=Vec::new();

    let alice=Box::new(Person::new("Alice", "alices@example.com"));
    let bob=Box::new(Person::new("Bob", "bob@example.com"));
    let acme=Box::new(Organization::new("Acme Inc.","123 Main Str."));

    elements.push(alice);
    elements.push(acme);
    elements.push(bob);


    let mut email_visitor=EmailVisitor;
    for element in elements {
        element.accept(&mut email_visitor);
    }
}
1,首先,我们定义一个Vector元素,其类型为Vec<Box<dyn Element>>。为什么是dyn Element?因为Element是一个trait,需要动态调度,因为我们不知道要存储的元素的大小。毕竟,我们只知道它们实现了Element特性。
2,接下来,我们实例化三个结构体,一个Organization和两个Persons,我们将它们push到Vector上。
3,我们实例化了EmailVisitor。
4,通过调用accept方法遍历元素并访问它们。

执行cargo run,结果如下:
Sending email to Alice at alices@example.com
Sending mail to Acme Inc. at 123 Main Str.
Sending email to Bob at bob@example.com

用户评论