首页 > 解决方案 > 策略模式可以包含对父类的引用吗?

问题描述

我正在尝试在我的代码中实现策略模式,但我遇到了我见过的示例中未涵盖的内容。这就是策略需要引用父类中包含的方法的时候。

对于简单的示例(没有父引用),让我们使用DuckandQuackBehaviour示例:

class RubberDuck extends Duck {

  public RubberDuck() {
    setQuackBehaviour(new Squeak());
  }

}

class Squeak implements QuackBehaviour {

  public String quack() {
    return "QUACK!";
  }

}

但是,如果我们现在有一只喜欢说自己名字的鸭子呢?这意味着 QuackBehaviour 需要对鸭子本身进行某种参考。

class PsyDuck extends Duck {

  public PsyDuck() {
    setQuackBehaviour(new SayName(this));
  }

}

class SayName implements QuackBehaviour {

  private Duck duck;

  public SayName(Duck duck) {
    this.duck = duck;
  }

  public String quack() {
    return duck.getName();
  }

}

这对我来说就像是糟糕的代码。这是反模式吗?它可以防止 QuackBehaviour 被非 Duck 对象重用。而关于类之间的相互依赖关系的一些事情并不适合我。

我想你也可以传入一个函数来PsyDuck喜欢:

class PsyDuck extends Duck {

  public PsyDuck() {
    setQuackBehaviour(new SayName(() => this.getName()));
  }

}

但是,如果我们开始要求行为中的多个字段,那么我们将不得不传入许多函数参数。

还是最好有SayName一个抽象类并PsyDuck实现一个具体版本?

class PsyDuck extends Duck {

  public PsyDuck() {
    setQuackBehaviour(new PsyDuckSayName());
  }

  class PsyDuckSayName extends SayName {

    protected String getName() {
      return PsyDuck.this.getName();
    }

  }

}

abstract class SayName implements QuackBehaviour {

  public String quack() {
    return getName();
  }

  protected abstract String getName();

}

最后一种方法似乎最干净,但我希望得到一些反馈和建议。

标签: javastrategy-pattern

解决方案


我不认为它本身是一种反模式。通常,您使用策略模式从类(或者更确切地说,一个实例)外部提供“逻辑”,因此如果您这样编写它会变得更清晰一些(尽管直接在您的子类中使用它也可以) :

Duck duck = new WhateverDuck();
duck.setQuackBehaviour(new SayNameBehaviour(duck));
// or:
duck.setQuackBehaviour(new MeowBehaviour());

因此,如何实现 quack 对鸭子实现无关紧要。如果实现需要鸭子引用来执行其工作 - 就这样吧。如果没有 - 很好。

其他常用模式定义了“策略”实现所期望的参数,因此您可以将您的quackBehavioureg 声明为 type Function<Duck, String>。实现仍然可以选择忽略该参数。但这对可能(和不可能)的实现做出了一些假设,应该谨慎使用。在您的情况下,我更喜欢第一个变体。


推荐阅读