我如何编写策略模式的 Rust 变体,其中给定结构拥有修改原始结构的策略?

How can I write this Rust variation on strategy pattern in which a given struct owns a strategy that modifies the original struct?

为复杂的标题道歉!

我是 Rust 的新手,我正在尝试解决一个非常具体的问题。 None 迄今为止我尝试过的解决方案似乎在语言范围内运行良好。

我有一个包含数据的结构(称为模型),它还包含一个用于“策略”结构的动态框。有几种不同的策略结构,它们由一个共同的特征(策略)标识,每个特征都包含通过其“执行策略”方法修改模型的单独方式。通过这样做,我可以通过更改模型的策略实例来动态更改使用的策略,如 state-machine.

每个策略都是不可变的,但它们会改变模型的数据。它们有时确实包含自己的不可变数据,因此枚举似乎不太合适。

trait Strategy {
   fn execute_strategy(&self, model: &mut Model);
}

struct Strategy1;

impl Strategy for Strategy1 {
   fn execute_strategy(&self, model: &mut Model) {
      ...
   }
}

struct Strategy2;

impl Strategy for Strategy2 {
   fn execute_strategy(&self, model: &mut Model) {
      ...
   }
}

struct Model {
   strategy: Box<dyn Strategy>,
}

现在我 运行 遇到的问题是执行策略。

impl Model {
   fn run(&mut self) {
      (*self.strategy).execute_strategy(self); // WONT COMPILE
   }
}

我明白了为什么上面的代码无法编译——它看到 self 是不可变和可变地借用的。有没有惯用的解决方案?每个策略都在真空中工作,只修改模型。策略本身是不可变的,因此执行上述操作似乎是安全的。

新年快乐,在此先感谢您的帮助!

我不知道解决这个问题最惯用的方法是什么,但我能想到一些。一种方法是从 self 中删除 strategy,这样它在操作期间就不是 self 的成员,然后再放回去。这似乎是一种反模式,因为您可能会忘记事后将其放回原处(尤其是当您忘记处理错误时):

impl Model {
    fn run(&mut self) {
        let strategy = std::mem::replace(&mut self.strategy, Box::new(EmptyStrategy {}));
        strategy.execute_strategy(self);
        let _ = std::mem::replace(&mut self.strategy, strategy);
    }
}

请注意,如果您使用 Option<Box<dyn Strategy>>,则有一个更好的 API:您可以使用 self.strategy.take() 获取(并删除)该成员,并将该成员替换为 self.strategy.replace()(或作业)。但这并不能解决安全问题。

如果您的结构只有 1-2 个成员,更好的方法是让策略对这些成员而不是结构本身进行操作。您可以按如下方式解构结构和 运行 策略:

impl Model {
    fn run(&mut self) {
        let Model {
            data,
            data2,
            strategy,
        } = self;
        strategy.execute_strategy(data, data2);
    }
}

最通用和最安全的解决方案可能是将策略存储在 RcArc 中,然后制作一个新的参考副本以执行该策略:

struct Model {
    strategy: Arc<Box<dyn Strategy>>,
}

impl Model {
    fn run(&mut self) {
        self.strategy.clone().execute_strategy(self);
    }
}