Какие принципы SOLID нарушаются?

ВВЕДЕНИЕ


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

Как в следующем примере:

ПРИМЕР


public static String getAnimalNoise(Animal animal) {
  if (animal instanceof Dog)
    return "Woof";
  if (animal instanceof Cat)
    return "Miau";
  return "";
}

Метод возвращает String "Woof", если данный экземпляр Animal является Dog и "Miau", если это Cat. Пустая строка, потому что некоторые животные вообще не издают звуков.

Поэтому правильным решением для этого должно быть использование полиморфизма с getNoise методом в классе Animal.

Я проанализировал различные индикаторы проблем наследования и хочу сказать, нарушают ли некоторые из них SOLID принцип < / а>.

Я думал, что приведенный выше пример нарушает:

  1. Принцип единой ответственности (SRP)
  2. Принцип открытости / закрытости (OCP)
  3. Принцип замещения Лискова (LSP)
  4. Принцип инверсии зависимостей (DIP)

Но я не совсем уверен, верно ли это для всех.

Я думал:

ПРИНЦИПНЫЕ НАРУШЕНИЯ


Нарушение SRP

Потому что условные операторы вообще нарушают SRP, потому что, как оператор switch case или несколько операторов if-else, считаются более чем одной обязанностью.

Существует два случая, поэтому есть несколько причин для изменения метода.

Нарушение OCP

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

НАРУШЕНИЕ LSP

Каждая ветвь выполняет разные действия в зависимости от подтипа животных. Что, по моему мнению, нарушает LSP ?! Я знаю пример прямоугольника, квадрата и getArea, но этот пример, как я думал, также подходит для нарушения.

НАРУШЕНИЕ ПОГРУЖЕНИЯ

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

ВОПРОС:


Итак, для данного примера вопрос заключается в том, действительно ли нарушаются данные принципы и верны ли рассуждения?


person Zelldon    schedule 03.06.2015    source источник
comment
Это может быть больше по теме Programmers.SE.   -  person MSalters    schedule 03.06.2015


Ответы (2)


SRP Потому что условные операторы вообще нарушают SRP, потому что, как оператор switch case или несколько операторов if-else, считаются более чем одной обязанностью. Существует два случая, поэтому есть несколько причин для изменения метода.

Я категорически не согласен. SRP следует интерпретировать с долей скептицизма. Прочтите статью об этом дяди Боба - он придумал этот принцип.

Процитирую важные моменты:

Что определяет причину изменений?

Это принцип о людях.

Когда вы пишете программный модуль, вы хотите быть уверенным, что при запросе изменений эти изменения могут исходить только от одного человека или, скорее, от одной тесно связанной группы людей, представляющих одну узко определенную бизнес-функцию. Вы хотите изолировать свои модули от сложностей организации в целом и спроектировать свои системы таким образом, чтобы каждый модуль отвечал (отвечал) на потребности только одной бизнес-функции.

[...] размышляя об этом принципе, помните, что причины перемен - это люди. Это люди, которые требуют изменений. И вы не хотите сбивать с толку этих людей или себя, смешивая воедино код, который волнует множество разных людей по разным причинам.


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

Верный. Этот метод предполагает определенный набор реализаций и не сможет обрабатывать новые без изменения.


LSP Каждая ветвь выполняет разные действия в зависимости от подтипа животных. Что, как мне кажется, нарушает LSP ?!

Это нарушает LSP, но по другой причине. Если бы я передал жирафа, я бы получил неожиданный результат - пустую строку. Это означает, что метод не подходит ни для одного подтипа Animal.


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

Технически верно, но это всего лишь побочный эффект нарушения двух других принципов, указанных выше. Это не совсем суть проблемы.


Помните, что принципы - это не правила, поэтому не будьте слишком строгими / буквальными при их толковании. Ключевыми факторами являются прагматизм и понимание почему принципа.

person dcastro    schedule 03.06.2015
comment
Я бы добавил DIP: метод должен зависеть от MakesNoiseInterface, а не от конкретных классов. - person deceze♦; 03.06.2015
comment
@deceze Интерфейс не нужен, абстракция уже существует: Animal. Проблема заключается в проверке типов для конкретных животных, и я бы лично решил ее, переместив метод getNoise внутрь Animal, устраняя все 3 нарушения. - person dcastro; 03.06.2015
comment
Большое спасибо за быстрый ответ! Что касается SRP, я думаю, вы ошибаетесь, см. "Книгу Роберта К. Мартина" на сайте "Чистый код" 38 ›У этой функции есть несколько проблем. Во-первых, он большой, и когда будут добавлены новые типы сотрудников, он будет расти. Во-вторых, он явно делает больше, чем одну вещь. В-третьих, он нарушает принцип единой ответственности7 (SRP), потому что есть несколько причин для его изменения. Вот ссылка на чистый код: cleansourcecode.files.wordpress.com/2013/ 10 / clean-code.pdf - person Zelldon; 03.06.2015
comment
@Zelldon Роберт С. Мартин - дядя Боб, о чьей статье я упоминал ^^ Я не думаю, что есть более чем одна причина для изменений. Имея в виду статью, можете ли вы назвать две или более причин для ее изменения, исходящих от разных людей из разных отделов / разных бизнес-требований? - person dcastro; 03.06.2015
comment
Я знаю, что он есть. Скажем, вы хотите изменить шум собаки, одна из причин для меня, вторая причина - это шум кошки, чтобы измениться, и третья причина, по которой животное должно возвращать не пустую строку для шума чего-то в этом роде. - person Zelldon; 03.06.2015
comment
Одна и та же причина - изменение шума собаки, кошки или любого другого животного. Это те же бизнес-требования. (..) помните, что причиной перемен являются люди. Это люди, которые требуют изменений. Человек, которого волнует шум, производимый кошкой, также заботится о том, какой шум издает собака. - person dcastro; 03.06.2015
comment
Хорошо, возможно, вы правы, я думаю, что пример тоже неуместен. - person Zelldon; 03.06.2015
comment
Я бы лично решил эту проблему, переместив метод getNoise внутрь Animal - по сути, это то, что я хотел выразить в приведенном выше комментарии. Функциональность должна быть выражена с помощью интерфейса [что неявно означает, что у самого объекта есть метод, который вы можете вызвать]. - person deceze♦; 03.06.2015
comment
@deceze Тогда мы на одной странице :) - person dcastro; 03.06.2015

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

Пусть Φ (x) - свойство, доказуемое для объектов x типа T. Тогда Φ (y) должно быть истинным для объектов y типа S, где S - подтип T.

Учитывая два производных от Animal, а именно Dog и Cat и ваш метод getAnimalNoise, вы не принимаете решений относительно некоторого доказуемого свойства конкретного объекта. Ваш метод решает, какой шум должен быть возвращен, а не сами объекты.

Итак, давайте представим, что вы можете установить количество ног для животного.

Animal a = new Animal()
a.setLegFront(2);
a.setLegRear(2);

И если ваш Dog перезапишет это так:

 class Dog extends Animal
 {
   public void setFrontLegs(int legs)
   {
     this.frontLegs = legs;
     this.rearLegs = legs + 2; 
   }
   public void setRearLegs(int legs)
   {
     // do nothing here for demonstration purposes
   }
 }

Если теперь у вас есть завод, возвращающий Animal

Animal createAnimal()
{
   return new Dog();
}
Animal a = createAnimal();
a.setFrontLegs(2);
a.setRearLegs(2);

И вы вызываете методы setFront/setRearLegs, вы ожидаете, что результаты будут 2 и 2, но на самом деле результат совершенно другой, а именно 2 и 4. Таким образом, этот пример тесно связан с обычным примером LSP с квадратами и прямоугольниками. Но для меня это более точный пример нарушения доказываемых свойств, чем в вашем примере.

Обновление для других принципов

Я согласен с вами, что другие принципы также нарушаются, но в отношении SRP я согласен с @dcastro.

person ckruczek    schedule 03.06.2015
comment
Спасибо. А как насчет других принципов? - person Zelldon; 03.06.2015