Существуют ли варианты ООП, в которых некоторые или все принципы SOLID противоположны чистому коду?


26

Недавно у меня был разговор с моим другом об ООП в разработке видеоигр.

Я объяснял архитектуру одной из моих игр, которая, к удивлению моего друга, содержала много небольших классов и несколько уровней абстракции. Я утверждал, что это было результатом того, что я сосредоточился на том, чтобы дать всем Единую Ответственность, а также ослабить связь между компонентами.

Его беспокоило то, что большое количество занятий перерастет в кошмар обслуживания. На мой взгляд, это будет иметь совершенно противоположный эффект. Мы продолжали обсуждать это в течение, казалось бы, столетий, в конце концов соглашаясь не соглашаться, говоря, что, возможно, были случаи, когда принципы SOLID и надлежащий ООП фактически не смешивались.

Даже статья в Википедии о принципах SOLID гласит, что они являются руководящими принципами, которые помогают в написании поддерживаемого кода, и что они являются частью общей стратегии гибкого и адаптивного программирования.

Итак, мой вопрос:

Есть ли в ООП случаи, когда некоторые или все принципы SOLID не пригодны для очистки кода?

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

Есть ли другие? Возможно, определенные типы проектов или определенные целевые платформы работают лучше с менее твердым подходом?

Редактировать:

Я просто хотел бы указать, что я не спрашиваю, как улучшить мой код;) Единственная причина, по которой я упомянул проект в этом вопросе, - дать немного контекста. Мой вопрос о ООП и принципах проектирования в целом .

Если вам интересно узнать о моем проекте, посмотрите это .

Изменить 2:

Я предполагал, что на этот вопрос ответят одним из 3 способов:

  1. Да, существуют принципы проектирования ООП, которые частично противоречат SOLID
  2. Да, существуют принципы проектирования ООП, которые полностью противоречат SOLID
  3. Нет, SOLID - это колени пчелы, и ООП всегда будет лучше с ним. Но, как и во всем, это не панацея. Пить ответственно.

Варианты 1 и 2, вероятно, дали бы длинные и интересные ответы. Вариант 3, с другой стороны, будет коротким, неинтересным, но в целом обнадеживающим ответом.

Мы, кажется, сходимся к варианту 3.


Как вы определяете «чистый код»?
GrandmasterB

Чистый код в рамках этого вопроса представляет собой структуру кода, которая соответствует целям ООП и набору выбранных принципов проектирования. Итак, я знаком с чистым кодом с точки зрения целей, поставленных OOP + SOLID. Мне интересно, есть ли другой набор принципов проектирования, которые работают с ООП, но полностью или частично несовместимы с SOLID.
MetaFight

1
Я гораздо больше беспокоюсь о производительности вашей игры, чем о чем-либо еще. Если только речь не идет о текстовой игре.
Эйфорическая

1
Эта игра по сути эксперимент. Я пробую разные подходы к разработке и пытаюсь понять, может ли корпоративный код работать при написании игры. Я ожидаю, что производительность станет проблемой, но пока нет. Если / когда это произойдет, то следующая вещь, с которой я буду экспериментировать, - это как адаптировать мой код в исполняющий код. Так много обучения!
MetaFight

1
Рискнув некоторых отрицательных голосов, я хотел бы вернуться к вопросу «почему»: ООП в разработке игр . В связи с характером развития игры, «традиционный» ООП , кажется, падает из моды в пользу различных вкусов сущностей / компонент системы, интересный вариант здесь , например. Это скорее заставляет меня думать, что вопрос должен быть не «SOLID + OOP», а «OOP + Game Development». Когда вы смотрите на график взаимодействия объектов для игры Dev. По сравнению с N-уровневым приложением, различия могут означать, что новая парадигма хороша.
J Trana

Ответы:


20

Есть ли в ООП случаи, когда некоторые или все принципы SOLID не пригодны для очистки кода?

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

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

Короче говоря, принципы SOLID всегда пригодны для чистого кода, но в некоторых сценариях они дают меньше, чем конфликтующие альтернативы. Они всегда хороши, но иногда другие вещи более хороши.


14
Мне нравится, но иногда другие вещи лучше . У этого есть чувство "Животноводческой фермы" к этому. ;)
FrustratedWithFormsDesigner

12
+1 Когда я только что посмотрел на принципы SOLID, я увидел 5 «хорошо иметь». Но ни один из них не стоит на вершине «СУХОЙ, ПОЦЕЛУЙ» и «проясни свои намерения» Используйте SOLID, но проявите некоторую осторожность и скептицизм.
user949300

Я согласен. Я думаю, что правильный принцип (ы), которому нужно следовать, явно зависит от ситуации, но помимо жестких требований к производительности, которые всегда стоят выше всего остального (это особенно важно при разработке игр), я склонен думать, что DRY и KISS обычно оба важнее чем ТВЕРДЫЙ. Конечно, чем более чистым вы делаете код, тем лучше, поэтому, если вы можете следовать всем принципам без конфликтов, тем лучше.
Бен Ли,

А как насчет интеграции интеграции против эффективного проектирования агрегатов? Если базовый «последовательный» интерфейс [например, IEnumerable] включает в себя такие методы, как Countи asImmutable, и свойства, такие как getAbilities[чье возвращение будет указывать, будут ли такие вещи Count«эффективными»], тогда можно иметь статический метод, который принимает несколько последовательностей и объединяет их так, чтобы они Вы будете вести себя как одна более длинная последовательность. Если такие способности присутствуют в базовом типе последовательности, даже если они связаны только с реализациями по умолчанию, тогда совокупность сможет раскрыть эти способности ...
суперкат

... и эффективно реализовывать их при использовании с базовыми классами, которые могут это сделать. Если один объединяет список из десяти миллионов элементов, который знает его количество, и список из пяти элементов, который может только извлекать элементы последовательно, запрос для записи 10 000 003-й должен считать число из первого списка, а затем прочитать три элемента из второго , Интерфейсы кухонной раковины могут нарушать работу интернет-провайдера, но они могут значительно улучшить производительность некоторых сценариев компоновки / агрегации.
суперкат

13

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

Многие программисты, с которыми я встречался в играх, были ужасны в Software Engineering, но им не нужны были такие практики, как SOLID. Традиционно они помещают свою игру в коробку - тогда они сделаны.

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

Оба приведенных выше утверждения, конечно, являются чрезмерными обобщениями, но на самом деле в обоих случаях чистый код является критическим. Для оптимизации необходим простой и понятный код. Ради удобства, вы хотите то же самое.

Нельзя сказать, что SOLID не без критики. Их называют принципами, и, тем не менее, они должны следовать принципам? Так когда именно я должен следовать за ними? Когда я должен нарушать правила?

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

Нельзя сказать, что «большое количество классов может привести к кошмару обслуживания». Однако, если SRP интерпретируется неправильно, вы легко можете столкнуться с этой проблемой.

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

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

Open-Closed не без своих критиков. Например, см. Обзор Джона Скита по принципу открытого закрытого типа . Я не буду воспроизводить его аргументы здесь.

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

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

DIP может привести к неработоспособному коду. Я видел классы с огромным количеством параметров от имени DIP. Эти классы обычно «обновляют» свои составные части, но я называю способность к тестированию, что мы никогда не должны снова использовать ключевое слово new.

SOLID сам по себе недостаточно для написания чистого кода. Я видел книгу Роберта К. Мартина « Чистый код: руководство по гибкому программному обеспечению ». Самая большая проблема в том, что эту книгу легко читать и интерпретировать как правила. Если вы делаете это, вы упускаете суть. Он содержит большой список запахов, эвристик и принципов - гораздо больше, чем просто пять из SOLID. Все эти «принципы» на самом деле не принципы, а руководящие принципы. Дядя Боб сам описывает их как "дырки" для понятий. Они уравновешивают; слепое следование любым указаниям вызовет проблемы.


1
Если у вас есть большое количество параметров конструктора, это говорит о том, что вы нарушили SRP. Тем не менее, контейнер DI в любом случае устраняет боль, связанную с большим количеством параметров конструктора, поэтому я не согласен с вашими утверждениями о DIP.
Стивен

Все эти «принципы» на самом деле не принципы, а руководящие принципы. Они уравновешивают; как я уже сказал в своем посте после SRP, сама по себе крайность может быть проблематичной.
Дэйв Хиллиер,

Хороший ответ, +1. Я хотел бы добавить одну вещь: я прочитал рецензию Скита больше на критику стандартного определения OCP в учебниках, а не на основные идеи, лежащие в основе OCP. Насколько я понимаю, идея защищенного варианта - это то, чем должна была быть OCP с самого начала.
Док Браун

5

Вот мое мнение:

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

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

Я полагаю, что принципы SOLID не противоречат ООП, но все же возможно написать неочищенный код, придерживающийся их.


3
+1 По определению почти очень гибкая система должна быть менее ремонтопригодной, чем менее гибкая. Гибкость достигается за счет дополнительной сложности, которую она приносит.
Энди

@ Не обязательно. на моей нынешней работе большая часть худших частей кода является грязной, потому что она просто объединяется, «делая что-то простое, просто взломайте это и сделайте так, чтобы оно не стало таким сложным». В результате многие части системы на 100% жесткие. Вы не можете изменить их вообще, не переписывая большие их части. Это действительно трудно поддерживать. Ремонтопригодность обеспечивается высокой когезией и низким сцеплением, а не гибкостью системы.
Сара

3

В ранние годы разработки я начал писать Roguelike на C ++. Поскольку я хотел применить хорошую объектно-ориентированную методологию, которую я узнал из своего образования, я сразу же увидел, что игровые предметы - это объекты C ++. Potion, Swords, Food, Axe, И Javelinsт.д. все происходит от базового основного Itemкода, обработки имени, значка, вес, что таких вещей.

Затем я кодировал сумку логику и столкнулся с проблемой. Я могу положить Itemsв сумку, но тогда, если я выберу один, как я узнаю, если это Potionили Sword? Я посмотрел в Интернете, как убрать предметы. Я взломал опции компилятора, чтобы включить информацию времени выполнения, чтобы я знал, каковы мои абстрагированные Itemистинные типы, и начал переключать логику на типы, чтобы знать, какие операции я бы разрешил (например, избегать пить Swordsи ставить на Potionsноги)

По сути, он превратил код в большой шарик из полузакрытой грязи. Когда проект продолжался, я начал понимать, что было неудачей проекта. Случилось так, что я попытался использовать классы для представления значений. Моя классовая иерархия не была значимой абстракцией. Что я должен был сделать это делает Itemреализовать набор функций, таких , как Equip (), Apply (), и Throw (), и сделать каждый ведут себя на основе значений. Использование перечислений для представления игровых автоматов. Использование перечислений для представления различных видов оружия. Использование большего количества значений и меньше классификации, потому что у моего подкласса не было никакой другой цели, кроме как заполнить эти окончательные значения.

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


2
Проблема заключалась в путанице типов с классами значений (примечание: я не использую слово class для ссылки на понятие класса OOP / C ++.) Существует несколько способов представления точки в декартовой плоскости (прямоугольные координаты, полярные координаты) но они все являются частью одного типа. Однако основные языки ООП не поддерживают естественную классификацию значений. Наиболее близким к этому является объединение C / C ++, но вам нужно добавить дополнительное поле, чтобы просто знать, что вы там делаете.
Доваль

4
Ваш опыт может быть использован как анти-пример. Не используя SOLID и какую-либо методологию моделирования, вы создали не поддерживаемый и не расширяемый код.
Эйфорическая

1
@Euphoric Я очень старался. У меня была объектно-ориентированная методология. Хотя есть разница между методологией и успешной ее реализацией :)
Артур Гавличек

2
Как это пример принципов SOLID, противоречащих чистому коду в ООП? Это больше похоже на пример неправильного дизайна - это ортогонально ООП!
Андрес Ф.

1
В вашем базовом классе ITEM должно быть несколько логических методов canXXXX, все по умолчанию равны FALSE. Затем вы можете установить "canThrow ()" для возврата true в вашем классе Javelin и canEat () для возврата true для вашего класса Postion.
Джеймс Андерсон

3

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

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

Но проблема для меня, с которой я боролся в том, что, по крайней мере, можно было бы назвать несколько более похожей на SOLID-совместимую архитектуру (она была на основе COM), может грубо сводиться к «слишком большому количеству классов» или «слишком большому количеству функций», так как твой друг мог бы описать. Я бы конкретно сказал: «слишком много взаимодействий, слишком много мест, которые могли бы плохо себя вести, слишком много мест, которые могли бы вызвать побочные эффекты, слишком много мест, которые, возможно, нужно изменить, и слишком много мест, которые могли бы не делать то, что мы думаем, что они делают». «.

У нас было несколько абстрактных (и чистых) интерфейсов, реализованных множеством подтипов, вроде этого (сделал эту диаграмму в контексте обсуждения преимуществ ECS, не обращая внимания на нижний левый комментарий):

введите описание изображения здесь

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

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

введите описание изображения здесь

И вау! Это была такая разница с точки зрения ремонтопригодности. Зависимости перешли не к абстракциям , а к данным (компонентам). И, по крайней мере, в моем случае, данные были гораздо более стабильными и их было проще понять с точки зрения проектирования, несмотря на изменяющиеся требования (хотя то, что мы можем делать с одними и теми же данными, постоянно меняется с изменением требований).

Кроме того, поскольку объекты в ECS используют композицию вместо наследования, им фактически не нужно содержать функциональность. Они просто аналогичный «контейнер компонентов». Это сделало так, что аналогичные 200 подтипов, которые реализовали интерфейс движения, превращаются в 200 экземпляров сущности (не отдельные типы с отдельным кодом), которые просто хранят компонент движения (который является ничем иным, как данными, связанными с движением). A PointLightбольше не является отдельным классом / подтипом. Это не класс вообще. Это экземпляр объекта, который просто комбинирует некоторые компоненты (данные), связанные с тем, где он находится в пространстве (движение), и конкретными свойствами точечных источников света. Единственная функциональность, связанная с ними, находится внутри систем, таких какRenderSystem, который ищет компоненты света в сцене, чтобы определить, как визуализировать сцену.

С изменением требований в соответствии с подходом ECS часто возникала необходимость изменить только одну или две системы, работающие с этими данными, или просто ввести новую систему на стороне, или ввести новый компонент, если потребовались новые данные.

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

введите описание изображения здесь

Есть ли в ООП случаи, когда некоторые или все принципы SOLID не пригодны для очистки кода?

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

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

  1. Да, существуют принципы проектирования ООП, которые частично противоречат SOLID
  2. Да, существуют принципы проектирования ООП, которые полностью противоречат SOLID.

Я не уверен, является ли ECS действительно ароматом ООП. Некоторые люди определяют это таким образом, но я вижу, что это очень сильно отличается от характеристик связи и отделения данных (компонентов) от функциональности (систем) и отсутствия инкапсуляции данных. Если бы это считалось формой ООП, я бы подумал, что он очень сильно конфликтует с SOLID (по крайней мере, самые строгие идеи SRP, open / closed, подстановка liskov и DIP). Но я надеюсь, что это разумный пример одного случая и области, где самые фундаментальные аспекты SOLID, по крайней мере, так как люди обычно интерпретируют их в более узнаваемом контексте ООП, могут быть не применимы.

Крошечные классы

Я объяснял архитектуру одной из моих игр, которая, к удивлению моего друга, содержала много небольших классов и несколько уровней абстракции. Я утверждал, что это было результатом того, что я сосредоточился на том, чтобы дать всем Единую Ответственность, а также ослабить связь между компонентами.

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

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

взаимодействия

Я говорю «взаимодействия», а не «связывание» (хотя сокращение взаимодействий подразумевает уменьшение обоих), поскольку вы можете использовать абстракции для разделения двух конкретных объектов, но они по-прежнему взаимодействуют друг с другом. Они все еще могут вызывать побочные эффекты в процессе этого косвенного общения. И часто я нахожу, что моя способность рассуждать о правильности системы связана с этими «взаимодействиями» больше, чем с «связью». Минимизация взаимодействий, как правило, облегчает мне понимание всего с высоты птичьего полета. Это означает, что вещи вообще не разговаривают друг с другом, и в этом смысле ECS также имеет тенденцию действительно минимизировать «взаимодействия», а не просто связь с минимумом минимумов (по крайней мере, я не имею

Тем не менее, это может быть, по крайней мере, частично я и мои личные слабости. Я обнаружил, что самым большим препятствием для меня является создание систем огромного масштаба, и я до сих пор уверенно рассуждаю о них, перемещаюсь по ним и чувствую, что могу вносить любые потенциальные желаемые изменения в любом месте предсказуемым образом, это управление состоянием и ресурсами наряду с побочные эффекты. Это самое большое препятствие, которое начинает возникать при переходе от десятков тысяч LOC к сотням тысяч LOC к миллионам LOC, даже для кода, который я полностью создал самостоятельно. Если что-то замедлит меня до уровня выше всего, это чувство, что я больше не могу понять, что происходит с точки зрения состояния приложения, данных, побочных эффектов. Это' Это не роботизированное время, которое требуется для внесения изменений, которое замедляет меня настолько сильно, как неспособность понять все последствия изменений, если система выходит за пределы способности моего разума рассуждать об этом. И сокращение количества взаимодействий стало для меня наиболее эффективным способом, позволяющим значительно увеличить объем продукта и значительно расширить его возможности, при этом я лично не перегружен этими вещами, поскольку сокращение количества взаимодействий до минимума также уменьшает количество мест, которые могут даже возможно изменить состояние приложения и вызвать побочные эффекты существенно.

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

введите описание изображения здесь

... для этого, где только системы имеют функциональность (синие компоненты теперь являются просто данными, а теперь это диаграмма связи):

введите описание изображения здесь

И по этому поводу возникают мысли, и, возможно, есть способ создать некоторые из этих преимуществ в более подходящем контексте ООП, более совместимом с SOLID, но я пока не совсем нашел конструкции и слова, и я нахожу это Трудно, так как терминология я привык разбрасывать все, что непосредственно связано с ООП. Я продолжаю пытаться выяснить это, читая ответы людей здесь, а также стараюсь изо всех сил сформулировать свои собственные, но есть некоторые вещи, очень интересные в природе ECS, которые я не смог точно указать на это. может быть более широко применимым даже к архитектурам, которые его не используют. Я также надеюсь, что этот ответ не сработает как акция ECS! Я просто нахожу это очень интересным, так как проектирование ECS действительно сильно изменило мои мысли,


Мне нравится различие между взаимодействиями и связями. Хотя ваша первая диаграмма взаимодействия запутана. Это планарный график, поэтому не нужно пересекать стрелки.
D Drmmr

2

Принципы SOLID хороши, но KISS и YAGNI отдают приоритет в случае конфликтов. Целью SOLID является управление сложностью, но если применение самого SOLID делает код более сложным, это противоречит цели. Например, если у вас небольшая программа с несколькими классами, применение DI, сегрегация интерфейса и т. Д. Вполне может увеличить общую сложность программы.

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


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

1
Если KISS и YAGNI всегда имели приоритет, вы все равно должны кодировать цифры 1 и 0. Ассемблеры - это просто нечто, что может пойти не так. Ни KISS, ни YAGNI не указывают на две из многих затрат на проектные работы. Эта стоимость всегда должна быть сбалансирована с выгодой любой проектной работы. SOLID имеет преимущества, которые в некоторых случаях компенсируют затраты. Нет простого способа узнать, когда вы пересекли черту.
candied_orange

@CandiedOrange: Я не согласен с тем, что машинный код проще, чем код на языке высокого уровня. Машинный код в конечном итоге содержит много случайных сложностей из-за отсутствия абстракции, так что определенно не KISS решает написать типичное приложение в машинном коде.
JacquesB

@Jules: Да, композиция предпочтительнее, но она все равно требует от вас разработки оригинального класса таким образом, чтобы композицию можно было использовать для его настройки, поэтому вы должны делать предположения о том, какие аспекты необходимо настроить в будущем и какие аспекты не настраиваются. В некоторых случаях это необходимо сделать (например, вы пишете библиотеку для распространения), но это имеет свою стоимость, поэтому следование SOLID не всегда оптимально.
JacquesB

1
@JacquesB - правда. А OCP по своей сути противоположен YAGNI; как бы вы ни добивались этого, вам нужно спроектировать точки расширения, чтобы обеспечить дальнейшее улучшение. Найти подходящую точку баланса между двумя идеалами ... сложно.
Жюль

1

По моему опыту:-

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

Маленькие классы легче поддерживать, а сложность поддержания коллекции маленьких классов арифметически возрастает до количества классов.

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


0

Мне всегда трудно провести черту между «S» твердого тела и (может быть, старомодно) необходимостью дать объекту все знания о себе.

15 лет назад я работал с разработчиками Deplhi, у которых был святой Грааль, чтобы у них были классы, в которых было все. Таким образом, для ипотеки вы можете добавить страховки и платежи, а также доход и кредиты и налоговую информацию, и вы можете рассчитать налог на выплату, налог на вычет, и он может сериализоваться, сохраняться на диске и т. Д.

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

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

Кроме того, не всегда легко найти хорошие имена для классов, которые делают только крошечные вещи.

Так что я не уверен, что буква «S» всегда хорошая идея.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.