Может ли шаблон стратегии содержать ссылку на родительский класс? - PullRequest
1 голос
/ 23 марта 2020

Я пытаюсь реализовать шаблон стратегии в своем коде, но я столкнулся с чем-то, что не рассмотрено в примерах, которые я видел. И именно тогда стратегия должна ссылаться на метод, содержащийся в родительском классе.

Для простого примера (без родительского ссылки), давайте использовать пример Duck и QuackBehaviour:

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 объектом, не являющимся утиным. И что-то в отношении взаимозависимости между классами не устраивает меня.

Я думаю, вы могли бы также передать функцию в 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();

}

Последний подход кажется самым чистым, но я хотел бы получить некоторые отзывы и советы.

1 Ответ

1 голос
/ 23 марта 2020

Я не думаю, что это само по себе анти-паттерн. Обычно вы используете шаблон Стратегии для предоставления «logi c» извне класса (или, скорее, экземпляра), поэтому становится немного понятнее, если вы пишете его таким образом (хотя также хорошо использовать его непосредственно в ваши подклассы):

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

Так что реализация утки не имеет значения, как реализован кряк. Если реализация нуждается в ссылке на утку для выполнения своей работы - пусть будет так. Если нет - отлично.

Другие часто используемые шаблоны определяют параметр, ожидаемый реализацией «Стратегия», поэтому вы можете объявить свой quackBehaviour, например, как тип Function<Duck, String>. Реализация все еще может игнорировать этот параметр. Но это делает некоторые предположения о возможных (и невозможных) реализациях, и их следует использовать с осторожностью. В вашем случае я бы предпочел первый вариант.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...