Рубрики
Без рубрики

Краткий обзор объектно-ориентированного дизайна программного обеспечения

Автор оригинала: FreeCodeCapm Team.

Станислав Козловски.

Продемонстрировано путем реализации ролевых классов игры

Вступление

Большинство современных языков программирования поддерживают и поощряют объектно-ориентированные программирование (OOP). Несмотря на то, что в последнее время мы видим легкое смещение от этого, когда люди начинают использовать языки, которые не являются тяжело Под влиянием ООП (например, GO, RUST, ELIXIR, ELM, SCALA), у большинства еще есть объекты. Принципы проектирования, которые мы собираемся наброски, здесь применяются к языкам без ООП.

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

Раскрытие: Пример, который мы собираемся пройти, будет в Python. Примеры там, чтобы доказать точку и могут быть небрежными другими, очевидными способами.

Типы объектов

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

Есть три типа объектов:

1. Объект объекта

Этот объект обычно соответствует некоторому реальномую существу в проблемном пространстве. Скажем, мы строим ролевую игру (RPG), объект объекта будет нашим простым Герой класс:

Эти объекты обычно содержат свойства о себе (такие как Здоровье или mana ) и модифицируются через определенные правила.

2. Объект управления

Контроль объектов (иногда также называется менеджер объектов ) несут ответственность за координацию других объектов. Это объекты, которые Контроль и использовать другие объекты. Отличный пример в нашей аналогии RPG будет Бороться Класс, который контролирует два героя и делает их борьбой.

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

3. граничный объект

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

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

Бонус: Цена объекта

Значение объектов представляют собой простое значение в вашем домене. Они неизменны и не имеют личности.

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

Они могут быть классифицированы как подкатегория Сущность объекты.

Принципы дизайна ключей

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

Абстракция

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

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

Абстракция в вашем коде должна следовать за Правило минимум сюрприз Отказ Ваша абстракция не должна кого-либо удивить ненужным и несвязанным поведением/свойствами. Другими словами – это должно быть интуитивно понятно.

Обратите внимание, что наше Герой # Take_damage () Функция не делает что-то неожиданное, как удалить наш характер на смерть. Но мы можем ожидать, что это убить нашего персонажа, если его здоровье будет ниже ноль.

Инкапсуляция

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

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

На большинстве языков это делается через так называемый Модификаторы доступа (Частный, защищенный и так далее). Python – это не лучший пример этого, поскольку ему не хватает таких явных модификаторов, встроенных в среду выполнения, но мы используем конвенции для работы вокруг этого. _ Префикс до переменных/методов обозначает их как частные.

Например, представьте, что мы меняем наше Бой # _run_attack Способ вернуть булевую переменную, которая указывает, что бой превышает, а не поднять исключение. Мы будем знать, что единственный код, который мы могли бы сломаться, внутри Бороться Класс, потому что мы сделали метод частным.

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

Разложение

Разложение – это действие разделения объекта на несколько отдельных меньших деталей. Указанные детали легче понимать, поддерживать и программировать.

Представьте, что мы хотели включить больше функций RPG, такие как баффы, инвентаризация, оборудование и атрибуты характера на наших Герой :

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

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

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

Теперь, после разложения функциональности объекта нашего героя в Heroattributes , Героинвентрия , Герорация и Herobuff Объекты, добавление будущих функций будут проще, более инкапсулированы и лучше абстрагированы. Вы можете сказать, что наш код – это уборщик и понятнее о том, что он делает.

Есть три типа разложенных отношений:

  • Ассоциация – Определяет свободную связь между двумя компонентами. Оба компонента не зависят друг от друга, но могут работать вместе.

Пример: Герой и а Зона объект.

  • агрегация – определяет слабую «имеющую» отношения между целым и его частями. Считается слабым, потому что части могут существовать без целого.

Пример: Героинвентрия и Предмет Отказ А Героинвентрия может иметь много Предметы и Предмет может принадлежать к любому Героинвентрия (например, торговые предметы).

  • Состав – сильная «имеет» отношения, где целое и часть не могут существовать без друг друга. Части не могут быть разделены, так как целое зависит от этих точных частей.

Пример: Герой и Heroattributes Отказ Это атрибуты героя – вы не можете изменить своего владельца.

Обобщение

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

Сравнение может прояснить вещи: пока абстракция Уменьшает сложность, скрывая ненужные детали, Обобщение Уменьшает сложность, заменяя несколько объектов, которые выполняют аналогичные функции с одной конструкцией.

В данном примере мы обобщенные наши общие Герой и NPC Функциональность классов в общий предком под названием Сущность Отказ Это всегда достигается благодаря наследству.

Здесь вместо нашего NPC и Герой Классы реализуют все методы дважды и нарушают Сухой принцип Мы сократили сложность, перемещая их общую функциональность в базовый класс.

В качестве льгота – не переусердствуйте Наследование Отказ Многие опытные люди Рекомендую вам услугу Композиция над наследством Отказ

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

Состав

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

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

Композитный объект API должен скрывать свои внутренние компоненты и взаимодействия между ними. Подумайте о механических часах, у него есть три руки для отображения времени и одной ручки для настройки – но внутренне содержит десятки движущихся и взаимозависимых частей.

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

Давайте проиллюстрируем возможную проблему с чрезмерной наследующей функциональностью:

Мы просто добавили движение в нашу игру.

Как мы узнали, вместо дублирования кода мы использовали обобщение, чтобы поставить move_right и move_left функции в Сущность класс.

Хорошо, теперь, что если мы хотели представить крепления в игру?

Крепления также должны будут двигаться влево и вправо, но не имеют возможности атаковать. Подумайте об этом – они не могут даже не иметь здоровья!

Я знаю, что такое ваше решение:

Просто переместите Переместить логика в отдельный Подвижность или Движущийсяobject класс, который имеет только эту функциональность. Гора Класс может затем наследовать это.

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

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

Урай, состав!

Критическое мышление отказ от ответственности

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

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

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

Сплоченность, муфта и разделение опасений

Сплоченность

Сплоченность представляет собой четкость обязанностей в модуле или другими словами – его сложность.

Если ваш класс выполняет одну задачу и ничего больше или имеет четкую цель – этот класс имеет Высокая сплоченность Отказ С другой стороны, если он несколько неясен в том, что он делает или имеет более одной цели – у него есть Низкая сплоченность Отказ

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

Связь

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

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

Разделение проблем

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

Веб-страница является хорошим примером этого – у него есть три слоя (информация, презентация и поведение), разделенные на три места (HTML, CSS и JavaScript соответственно ).

Если вы снова посмотрите на RPG Герой Пример, вы увидите, что у него было много проблем в самом начале (применить баффы, рассчитать повреждение атаки, обрабатывать инвентаризацию, предметы оборудования, управлять атрибутами). Мы отделили эти проблемы через Разложение в больше сплоченность классы, которые Аннотация и Инкапсулировать их детали. Наше Герой Класс сейчас действует как Композитный объект и намного проще, чем раньше.

Заплатить

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

Эти принципы гарантируют, что наша система больше:

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

Резюме

Мы начали, представляя некоторые основные типы объектов высокого уровня (сущность, границу и контроль).

Затем мы изучили ключевые принципы в структурировании указанных объектов (абстракция, обобщение, состав, разложение и инкапсуляция).

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

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

Дальнейшие чтения

Шаблоны дизайна: элементы многоразового объектно-ориентированного программного обеспечения -Сгустимо самая влиятельная книга в поле. Немного датирован в его примерах (C ++ 98) Но узоры и идеи остаются очень актуальными.

Растение объектно-ориентированного программного обеспечения, руководствуясь тестами – Отличная книга, которая показывает, как практически применять принципы, изложенные в этой статье (и более), работая через проект.

Эффективный дизайн программного обеспечения – Лучший блог Notch, содержащий гораздо больше, чем проницательность дизайна.

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

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