Принципы программирования SOLID

43

Со временем я смог понять две части SOLID - «S» и «O».

«O» - я выучил принцип Open Closed с помощью модели наследования и стратегии.

«S» - я изучил принцип единой ответственности при изучении ORM (логика персистентности отбирается у объектов домена).

Аналогичным образом, какие области / задачи лучше всего изучать для других частей SOLID («L», «I» и «D»)?

Ссылки

  1. msdn - Опасность нарушения принципов SOLID в C #
  2. channel9 - Применение принципов SOLID в .NET / C #
  3. Принципы OOPS (ТВЕРДЫЕ Принципы)
LCJ
источник
25
обратите внимание, что все эти идеи - хорошие идеи, и вместе они очень хороши. но если вы примените их догматически, они принесут больше неудач, чем успехов.
3
OR-Mappers хороши для разделения интересов, а не принципа единой ответственности. См. Этот пост programmers.stackexchange.com/questions/155628/… для обсуждения различий.
Док Браун
1
@JarrodRoberson Да, именно поэтому их тщательно называют руководящими принципами . Также не забывайте об остальных принципах: adamjamesnaylor.com/2012/11/12/… (всего 11)
Адам Нейлор
2
Ссылка @AdamNaylor теперь 404ing, она была перемещена на adamjamesnaylor.com/post/…
mattumotu

Ответы:

54

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

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

Как отмечается в комментариях, есть еще одно очень хорошее чтение PDF - SOLID Software Development от Pablo .

Кроме того, есть несколько хороших книг, которые более подробно описывают принципы SOLID - Good Book по разработке программного обеспечения SOLID .

Редактируйте и комментируйте краткое резюме по каждому принципу:

  • «S» - принцип единой ответственности обусловлен потребностями бизнеса в разрешении изменений. «Одна причина для изменения» помогает вам понять, какие логически отдельные концепции следует объединять, рассматривая бизнес-концепцию и контекст, а не только техническую концепцию. In another wordsЯ узнал, что каждый класс должен нести одну ответственность. Ответственность заключается в том, чтобы просто выполнить поставленную задачу

  • «О» - я выучил принцип Open Closed и начал «предпочитать композицию, а не наследование» и, как таковой, предпочитая классы, которые не имеют виртуальных методов и, возможно, запечатаны, но зависят от абстракций для их расширения.

  • «L» - я изучил принцип подстановки Лискова с помощью шаблона репозитория для управления доступом к данным.

  • «Я» - я узнал о принципе разделения интерфейсов, узнав, что клиенты не должны принуждаться к реализации интерфейсов, которые они не используют (как в поставщике членства в ASP.NET 2.0). Поэтому интерфейс не должен иметь «много обязанностей»
  • «D» - я узнал о принципе инверсии зависимостей и начал писать код, который легко изменить . Легче изменить означает более низкую совокупную стоимость владения и более высокую ремонтопригодность.

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

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

Е.Л. Юсубов
источник
3
Я нашел следующую коллекцию статей очень полезной: lostechies.com/wp-content/uploads/2011/03/…
Scroog1
Я прочитал всю эту статью, и меня не продают по шаблонам или по ТВЕРДОМУ. Пример слишком упрощен, но когда он становится сложным, эта сложность является искусственной. Мне еще предстоит столкнуться с реальным миром SOLID OOP без лучших альтернатив.
Работа
3
так как статьи о lostechies были упомянуты здесь, есть также этот solidexamples.codeplex.com (основанный на lostechies)
темный фейдер
2
Я был одним из авторов электронных книг Pablos. Я рад, что люди все еще находят это полезным. :)
Шон Чемберс
1
+1000000, если бы я мог за ваше краткое изложение принципа Открыто-Закрыто - каждый ошибается и думает, что речь идет о наследовании
AlexFoxGill
11

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

StriplingWarrior
источник
2
+1 это очень верно. Вам даже не нужно придерживаться (imo) иногда слишком строгого правила «модульный тест должен проверять только одну вещь»: если вы не можете создать приличный набор тестов для класса за пару минут, это нарушает I и D и, вероятно, остальную часть alfabet
stijn
8

Принцип подстановки Лискова в принципе не позволяет вам чрезмерно использовать наследование реализации: вы никогда не должны использовать наследование только для повторного использования кода (для этого есть состав)! Придерживаясь LSP, вы можете быть уверены, что между вашим суперклассом и вашим подклассом действительно существуют отношения «есть отношения».

Это говорит о том, что ваши подклассы должны реализовывать все методы подкласса аналогично реализации методов в подклассе. Вы никогда не должны переопределять метод с реализацией NOP или возвращать нуль, когда супертип генерирует исключение; указанные в Условиях проектирования по контракту, вы должны соблюдать контракт метода из суперкласса при переопределении метода. Способ защиты от нарушения этого принципа состоит в том, чтобы никогда не отменять реализованный метод; вместо этого извлеките интерфейс и реализуйте этот интерфейс в обоих классах.

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

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

Вы можете видеть Инверсию Зависимости в Заводском Образце; здесь и компонент высокого уровня (клиент), и компонент низкого уровня (отдельный экземпляр, который будет создан) зависят от абстракции(интерфейс). Способ применить его в многоуровневой архитектуре: вы не должны определять интерфейс для слоя в слое, который реализован, а в вызываемом модуле. Например, API для уровня источника данных должен быть записан не на уровне источника данных, а на уровне логики бизнеса, где он должен быть вызван. Таким образом, уровень источника данных наследует / зависит от поведения, определенного в бизнес-логике (таким образом, инверсия), а не наоборот (как было бы в обычном порядке). Это обеспечивает гибкость проектирования, позволяя бизнес-логике работать без каких-либо изменений кода с другим совершенно другим источником данных.

m3th0dman
источник
1
Отличное объяснение по Лискову. :)
Джон Корснес