Strategy模式的Java消费者接口的Rust等效项

0lvr5msh  于 2023-01-29  发布在  Java
关注(0)|答案(1)|浏览(124)

我将提供一个实际的例子。
我想创建一个事件记录器。我将一个事件定义为一个接口:

import java.util.function.Consumer;

interface Event {}

class BuyEvent implements Event {}

class SellEvent implements Event {}

日志记录器只是事件的消费者:

public static void main(String[] args) {
        Consumer<Event> logger;

        // Logger with method reference
        logger = System.out::println;
        logger.accept(new BuyEvent());

        // Logger with lambda
        logger = (event) -> {
            // Do something else
            System.out.println(event);
        };
        logger.accept(new BuyEvent());

我还可以创建一个带有状态的日志记录器。例如:

class StatefulLogger implements Consumer<Event> {
    public StatefulLogger() {
    }

    @Override
    public void accept(Event event) {
        // Change state, then print event
        System.out.println(event);
    }
}

我可以按如下方式使用状态记录器:

public static void main(String[] args) {
        Consumer<Event> logger = new StatefulLogger("foo.txt");
        logger.accept(new BuyEvent());
}

我也在努力实现同样的目标。
我将事件定义为枚举:

#[derive(Debug)]
enum Event {
    BuyEvent,
    SellEvent,
}

我定义了一个Logger trait和一个带有状态的struct来实现这样的trait:

trait Logger {
    fn accept(&mut self, ev: Event);
}

struct StatefulLogger {}

impl Logger for StatefulLogger {
    fn accept(&mut self, ev: Event) {
        // Change state, then print event
        println!("{:?}", ev);
    }
}

我可以按如下方式使用记录器:

fn main() {
    let logger: &dyn Logger = &ComplexLogger {};
}

我希望能够为日志记录器分配一个闭包,这与Java的精神非常相似。

fn main() {
    let consumer: fn(Event) = |ev: Event| {
        println!("{:?}", ev);
    };
}

总结一下:
在Java中,我使用策略设计模式和消费者接口实现了一个日志记录器,日志记录器既可以是一个复杂的有状态对象,也可以是一个轻量级的lambda。
我也想在Rust中实现同样的功能,但是我不知道该怎么做。我在互联网上找不到类似的例子。另外,Rust是否提供了一个类似于Java的消费者接口?

ntjbwcob

ntjbwcob1#

在Rust中没有办法快速解决这个问题,但是你可以创建自己的宏来将lambda转换为Logger impl,然后返回它的对象。看看这个repo。如果你愿意,我可以很快写一个解决方案。另外,你可以将你的Logger trait改为struct,定义消费者的字段。它让你可以使用任何Fn(Event)作为消费者,也就是说,如果你有带状态的记录器,你可以把它移到lambda并传递它,或者直接传递一些fn。

#[derive(Debug)]
struct Event;

struct Logger<T>
where
    T: Fn(Event),
{
    consumer: T,
}

impl<T> Logger<T>
where
    T: Fn(Event),
{
    fn new(consumer: T) -> Self {
        Self { consumer }
    }

    fn accept(&self, event: Event) {
        (self.consumer)(event);
    }
}

struct StatefulLogger;

impl StatefulLogger {
    fn log(&self, event: Event) {
        println!("{:?}", event);
    }
}

fn log_fn(e: Event) {
    println!("{:?}", e);
}

fn main() {
    let foo = |e: Event| println!("{:?}", e);
    let logger_lambda = Logger::new(foo);

    let stateful_logger = StatefulLogger;
    let logger_struct = Logger::new(move |e| stateful_logger.log(e));

    let logger_fn = Logger::new(log_fn);

    logger_lambda.accept(Event);
    logger_struct.accept(Event);
    logger_fn.accept(Event);
}

关于消费者界面,看看Fn,FnMut和FnOnce特性。

相关问题