Является ли нарушением принципа Открыто-Закрыто обновление константы, представляющей реальное значение?

10

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

Указывает ли акт исправления этой константы на нарушение принципа Открыто-Закрыто , поскольку он постулирует, что класс должен быть закрыт для модификации?

Анализ Paradisys
источник
10
Программное обеспечение меняется, потому что реальный мир меняется. С другой стороны, превращение налогового процента в константу является не столько нарушением принципа открытого закрытого типа, сколько просто невежественным поступком. Процент налога является очевидным изменяемым элементом, который должен быть связан во время выполнения.
Ричард Чамберс
4
Я полностью согласен с Ричардом. Если вам нужно изменить код, чтобы исправить эту «константу», OCP - это наименьшая из ваших проблем.
Роберт Харви
3
То, что представляет собой нарушение OCP, является весьма субъективным, и в любом случае все это несколько устарело (поскольку наследование реализации больше не является наилучшей практикой). Это типичный вопрос, когда вы должны угадать, что думает человек, задававший вопрос.
Роберт
2
@DocBrown: что представляет собой «новое требование»? Вы показываете мне некоторый код, я могу указать на новые требования, которые, безусловно, потребуют изменения кода, независимо от того, насколько OCP-соответствие вам соответствует. Итак, вернемся к вопросу: если разработчик спросил об этом бизнес-эксперта, и не ожидается, что налоговая ставка будет меняться чаще, чем раз в пару лет, нет смысла делать ее настраиваемой или вводимой. Просто будь проще и готовься к тому, что знаешь . И для тех вещей, конечно, сделайте это внешним по отношению к классу. Так что это зависит .
Роберт
1
@ RobertBräutigam: моя точка зрения такова, что ИМХО не существует такой вещи, как «соответствие OCP», а только «соответствие OCP в контексте определенных категорий требований». Несомненно, может быть некоторая субъективность, к каким категориям должен быть компонент «Соответствие OCP». Но в случае, описанном в этом вопросе, насколько я понимаю, изменяющееся требование уже было определено, так что этот «класс расчета дохода» явно не подчиняется OCP в контексте этого конкретного требования.
Док Браун

Ответы:

14

OCP может быть лучше понят, если подумать о классах или компонентах, предоставляемых поставщиком A в какой-то библиотеке черного ящика, для использования пользователями B, C и D (обратите внимание, что это просто ментальная модель, которую я использую для ясности, не имеет значения, если в действительности единственным пользователем класса является сам А.).

Если B, C и D могут использовать или повторно использовать предоставленные классы для разных вариантов использования, без необходимости изменения исходного кода библиотеки, тогда компонент удовлетворяет требованиям OCP ( в отношении категории вариантов использования ). Есть разные способы для достижения этой цели, как

  • сделать класс наследуемым (обычно в сочетании с шаблоном метода шаблона или шаблоном стратегии)

  • предоставляя «точки внедрения» для внедрения зависимости

  • путем предоставления параметров конфигурации для класса или компонента (например, с помощью параметра конструктора «процент налога», как в вашем случае, или с помощью какого-либо другого механизма конфигурации)

  • может быть, другие средства, в зависимости от языка программирования или экосистемы

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

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

Поэтому, несмотря на то, что вам здесь говорят другие, ответ однозначно «да» , это будет нарушением OCP.

РЕДАКТИРОВАТЬ: кажется, между кем-то написал подробный пост в блоге именно на эту тему. Хотя некоторые его части можно было бы сформулировать лучше (как указал Дерек Элкинс), автор, как правило, разделяет мою точку зрения о том, что «выполнение OCP» - это не абсолютная собственность, а нечто, что можно оценить только в контексте определенного категории изменений требований.

Док Браун
источник
Итак, OCP обеспечивает расширяемое поведение для разных вариантов использования одним из трех перечисленных вами средств, верно? Но что, если пример ОП подразумевает, что что-то фундаментальное изменится? Я не знаю, из какой страны ОП, но в моей стране ставка налога не очень часто меняется. Это был плохой пример, но, возможно, он был намеренно извлечен в константе, чтобы подчеркнуть суть. Я почти уверен, что он не предназначен для конфигурирования или расширения. Так что, возможно, вопрос был о том, что «это не имеет ничего общего с запретом каких-либо изменений исходного кода поставщиком А».
Вадим Самохин
По крайней мере, я так понял. Бедный парень, который удалил свой принятый ответ, сделал это, я думаю. Вы видели это немного под другим углом - я понимаю вашу точку зрения и согласен с этим. Но, похоже, самый мудрый комментарий дал @Robert Bräutigam. До сих пор я не осознавал, что OCP ТАК субъективен.
Вадим Самохин
1
Думаю, если мне когда-нибудь зададут один и тот же вопрос, мне нужно будет ответить на один вопрос: «Это поведение должно быть как-то расширено или настроено?». Если да - то прямое изменение самого класса является нарушением OCP. Если нет - тогда OCP просто не применим в такой ситуации.
Вадим Самохин
1
@Zapadlo: Я думаю, что если компонент удовлетворяет требованиям OCP для класса требований, он не очень субъективен - в большинстве случаев довольно ясно, требует ли новое требование модификации исходного кода компонента или если компонент поддерживает это требование «. Возможные подходы к его реализации не ограничиваются первыми 3 способами, которые я перечислил, см. Мое редактирование. Ваше представление о субъективности может быть вызвано тем, что у OCP просто вводящее в заблуждение название и довольно плохо объясняется во многих учебниках.
Док. Браун
Мое представление о субъективности было вызвано тем фактом, что я не до конца понимал, что вы сказали, - но теперь я понимаю, наверное. Большое спасибо за проницательные комментарии и ваш ответ.
Вадим Самохин
4

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

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

В долгосрочной перспективе вы можете обнаружить, что налоговые вопросы требуют больше, чем просто процент - например, что в один прекрасный день налоговое законодательство является более сложным и требует нескольких процентов и некоторых констант (например, сумма менее 10 тыс. Долл., Облагаемая налогом в X%, в то время как остаток облагается налогом по Y%).

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

Различные стратегии (а также константы% и $) должны выбираться из файла конфигурации, и теперь добавление новой стратегии требует добавления нового кода, но не обязательно обновления существующего кода.

Каждая стратегия может знать, как анализировать / интерпретировать свои внешние аргументы конфигурации, а также как рассчитывать фактический налог.

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


Также посмотрите внедрение зависимости , где мы управляем этими вещами явно.

Эрик Эйдт
источник
1
Вопрос заключался не в том, является ли плохой идеей хоронить что-то вроде налогового процента в коде, я уверен, что это очевидно для большинства из нас (включая ФП). Вопрос был: "Это нарушает OCP?" Поэтому я не понимаю, как ваш ответ относится к этому вопросу.
Док Браун
1

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

Если ваш класс является экземпляром (то есть это не статический класс), создав свойство класса налоговой переменной, значение которого вводится через конструктор, вы также улучшите связность классов.

Короче говоря, ваш текущий дизайн делает ваш класс зависимым от константного значения, которое на самом деле не является константой (определяя константу как значение, которое никогда не изменится, несмотря ни на что, например, на значение PI). Это нарушает OCP. Измените дизайн, чтобы получить значение налога в качестве аргумента конструктора.

Кристофер Франциско
источник
0

Полностью согласен с @Becuzz, и я просто хочу подвести итог: OCP - это поиск повторно используемых (и, следовательно, полезных) абстракций, которые вводятся в класс. Таким образом, поведение класса изменяется не путем изменения его кода, а путем предоставления ему различных реализаций. Это предельно ясно из книги Роберта Мартина « Гибкая разработка программного обеспечения, принципы, шаблоны и практики », см. Соответствующую главу «Принцип открытого и закрытого типа», подраздел «Абстракция - ключ». Это разъясняет еще одно заблуждение, что поведение может быть изменено только с помощью наследования. Именно Бертран Мейер предложил в 1988 году в своей книге « Построение объектно-ориентированного программного обеспечения », а не Роберт Мартин.

Вадим Самохин
источник
-2

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

Zalomon
источник
«Недостаток дизайна» в том, что он нарушает принцип открытого закрытого типа, поскольку вам нужно перекомпилировать код для изменения константы?
Эрдрик Айронрос Роуз