Паттерн стратегии нарушает принцип подстановки Лискова - PullRequest
0 голосов
/ 12 сентября 2018

Я реализую Шаблон стратегии для реализации поведения различных типов уток. Вот код:

public interface IFlybehaviour 
{
  public void fly();
}
public class GeneralFlybehaviour
{
  public void fly()
  {
    Console.WriteLine("I can fly as a duck");
  }
}

public abstract class Duck
{
  IFlybehaviour flybehaviour;
  Duck()
  {
  }
  public void PerformFly()
  {
   flybehaviour.fly();
  }
}

public class SimpleDuck : Duck
{
  public SimpleDuck(IFlybehaviour flybehaviour)
  {
    flybehaviour = new GeneralFlybehaviour();
  }
}

In the main method
void main()
{
  Duck d = new SimpleDuck();
  d.PerformFly();
}

Это подчиняется как " Открытый закрытый принцип ", так и " Принцип замещения Лискова ", где я могу создать 50 различных типов уток, таких как SimpleDuck, FlyingDuck и т. Д.

Теперь мне нужен класс ComplicatedDuck, где он обладает особой способностью исполнять желания своих учеников, скажем:

//public class ComplicatedDuck extends Duck (Java)
    public class ComplicatedDuck : Duck 
    {
      public ComplicatedDuck(IFlybehaviour flybehaviour)
      {
        flybehaviour = new GeneralFlybehaviour();
      }

     public void GrantWishes()
     { 
       Console.WriteLine("Wish Granted")
     }
    }

С этим изменением мы знаем, что оно нарушает «принцип подстановки Лискова», когда этот подкласс не заменит его базовый класс полностью.

Предположим, если я добавлю еще одну функцию в "абстрактный класс Duck" , тогда все унаследованные члены по крайней мере должны предоставить реализацию, говорящую, что "я не даю особых желаний".

В этом сценарии, который является лучшим решением, добавление метода в классе ComplicatedDuck или расширение BaseClass

Примечание: та же концепция работает для Java, просто заменяя ":" на ключевое слово "Implements".

Ответы [ 3 ]

0 голосов
/ 12 сентября 2018

Это классический случай композиции против наследования.

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

Вы создаете интерфейс под названием IRadio, и для каждого автомобиля, в котором есть радио, вы украшаете его IRadio (при условии, что это C #), это композиция. Его легко проверить, есть ли в машине радио, просто проверьте IRadio, его легко включить в любом автомобиле, RadioEnabled.

Часть домой. Заставлять методы к производным классам, которые им не нужны, грязно. Тем не менее, делать все составным, когда это может быть производным, также является пустой тратой. вам нужно просто провести линию логически

0 голосов
/ 12 сентября 2018

Шаблон стратегии предполагает наличие различных реализаций для IFlyBehavior, а не наследование классов для Duck.

Одна проблема с вашим кодом заключается в том, что в базовом классе Duck у вас есть закрытое поле, которое никогда не используется. Он может использоваться только Duck, поэтому все наследующие типы не могут получить к нему доступ. Если вы PerformFly(), вы получите исключение NullReferenceException - всегда. Если вы хотите наследовать Duck, возможно, вы захотите взять IFlyBehavior в конструкторе Duck.

Также

flybehaviour = new GeneralFlybehaviour();

отчасти побеждает цель наличия паттерна стратегии, поскольку навязывает ему конкретную реализацию. Я полагаю, что вместо наследования от Duck вы бы использовали состав, если хотите использовать конкретную IFlyBehavior реализацию

0 голосов
/ 12 сентября 2018

Я думаю, вы просто пропустили наследование ComplicatedDuck от класса Duck.Это должно быть похоже на - ComplicatedDuck: Duck

  • Вы можете переместить существующий метод - public void GrantWishes () в абстрактный класс Duck.
  • Сделать его виртуальным с пустым определением.
  • В классе ComplicatedDuck переопределите поведение так, как вам нужно.
  • Ничего не предпринимайте в классе SimpleDuck.

, чтобы принцип подстановки не нарушался.

...