Читать книгу Введение в объектно-ориентированный дизайн с Java - Тимур Машнин - Страница 1
Введение
ОглавлениеЧто такое дизайн и архитектура программного обеспечения?
И как это может улучшить программные продукты?
Давайте рассмотрим сценарий.
Предположим, вы присоединяетесь к проекту, который находится уже в разработке некоторое время.
Вы смотрите на код проекта, и вы не можете понять, для чего предназначены эти куски кода, так как он плохо организован, и проектной документации не существует.
Вы даже не знаете, с чего начать.
Это все признаки того, что проект не был хорошо разработан с самого начала.
Или, допустим, вы сейчас работаете над персональным проектом.
Когда вы начинали, вы не были уверены, какая конкретно функциональность должна быть реализована, но тем не менее вы начали кодирование.
Для вас не имело значения, что код будет неорганизованным, потому что вы были единственным, кто работал над проектом.
И предположим, вы придумали замечательную новую функцию для своего продукта, но при ее реализации вы нарушили программу в других местах. И теперь вы должны все исправлять во многих местах своего кода.
Чего не произошло бы, если бы вы правильно и хорошо с самого начала спроектировали бы свой продукт.
И такие сценарии довольно часто встречаются в индустрии программного обеспечения, что показывает, почему дизайн и архитектура программного обеспечения так полезны.
В этом разделе вы узнаете, как применять принципы и паттерны дизайна и архитектуры для создания многоразовых и гибких программных систем. Вы узнаете, как задокументировать дизайн и архитектуру программного продукта визуально.
Итак, в чем разница между дизайном программного обеспечения и архитектурой программного обеспечения?
Роль дизайнера программного обеспечения или архитектора программного обеспечения может сильно отличаться от компании к компании.
На это влияют такие характеристики, как размер компании, объем проекта, опыт команды разработчиков, организационная структура и возраст компании.
В некоторых компаниях могут работать отдельные дизайнеры или архитекторы.
В других компаниях эта работа может выполняться членом или членами команды разработчиков.
И как правило, дизайнер программного обеспечения отвечает за определение программного решения для конкретной проблемы путем проектирования деталей отдельных компонентов и их обязанностей.
Дизайнер программного обеспечения отвечает за просмотр всей системы и выбор подходящих фреймворков, систем хранения данных, за решения и определения взаимодействий компонентов друг с другом.
И это подводит нас к основному различию между дизайном программного обеспечения и архитектором программного обеспечения.
Дизайнер программного обеспечения смотрит на аспекты системы более низкого уровня, тогда как архитектор программного обеспечения работает с более крупной картиной – с более высокими аспектами системы.
Подумайте об этом, как о проектировании здания.
Архитектор сосредотачивается на основных структурах и службах, в то время как дизайнер интерьера фокусируется на меньших пространствах внутри здания.
Дизайн программного обеспечения – это процесс превращения пожеланий и требований заказчика в рабочий код, который является стабильным и поддерживаемым в долгосрочной перспективе, и может быть развит и стать частью более крупной системы.
Архитектура программного обеспечения в первую очередь начинается с понимания того, в чем состоит бизнес-задача, которую должен решить клиент.
И основная задача заключается в том, чтобы выяснить, чего хочет клиент, тогда можно двигаться дальше.
Потому что, если вы понимаете задачу, вы можете начать думать о возможных решениях, а затем вы начинаете понимать, как будет выглядеть общее решение.
И архитектура важна, потому что, если вы ошибетесь, ваш проект не удастся.
Все просто.
Мы знаем это в области строительства, и мы это знаем в области программного обеспечения.
Архитектура – это понимание взаимосвязи между требованиями пользователя и способностью создавать систему, которая будет обеспечивать эти требования.
При этом самая большая проблема, с которой мы сталкиваемся, – это понимание проблемы клиента.
Что он действительно хочет сделать?
И во многих случаях клиент фактически не знает, что он хочет делать. Он приходит лишь с частичным пониманием, смутным чувством, что он может сделать что-то лучше.
И одна из первых задач состоит в том, чтобы помочь ему лучше понять его проблему.
Задача архитекторов программного обеспечения – это взаимодействие между продуктом, клиентом и инженерными командами.
Архитектор программного обеспечения похож на архитектора здания. И он отвечает за общую концептуальную целостность проекта.
Возможно, вы слышали термин «объектно-ориентированное моделирование».
Что это?
При решении задачи, объектно-ориентированное моделирование включает в себя практику представления ключевых понятий через объекты в вашем программном обеспечении.
И в зависимости от задачи многие концепции становятся отдельными объектами в программном обеспечении.
Подумайте об объектах.
Вокруг нас все объекты.
Почему вы должны использовать объекты для представления вещей в вашем коде?
Это способ держать ваш код организованным, гибким и многоразовым.
Объектный подход создает организованный код, содержа связанные детали и конкретные функции в разных, легко доступных местах.
Это создает гибкость, поскольку вы можете легко изменять детали модульным способом, не затрагивая остальную часть кода. Также вы можете повторно использовать разные части кода.
Давайте рассмотрим, как может выглядеть объектно-ориентированное моделирование.
Рассмотрим, например, помещение для семинаров.
Первый объект, который мы идентифицируем, является сама комната.
В комнате есть такие детали, как номер комнаты и места для сидения.
Также мы можем идентифицировать объекты, которые содержатся в этой комнате.
Существует множество физических объектов, такие как стул, стол, проектор и белая доска.
Каждый из этих физических объектов может быть представлен объектами в программном обеспечении.
И существуют конкретные детали, связанные с каждым объектом.
Проектор имеет характеристики, связанные с его производительностью, такие как разрешение и яркость.
И объекты также могут иметь индивидуальные обязанности или поведение.
Например, проектор принимает видеопоток и отображает изображение.
Вы можете думать о разработке программного обеспечения как о процессе, который берет задачу и создает решение с помощью программного обеспечения.
И как правило, это итеративный процесс, при этом каждая итерация берет набор требований для реализации и тестирования и в конечном итоге создается полное решение.
Многие разработчики стремятся сразу кодировать, несмотря на то, что не полностью понимают, что программировать в первую очередь.
И погружение прямо в работу по реализации является основной причиной отказа проекта.
Если вы не хотите, чтобы ваши проекты потерпели неудачу, найдите время, чтобы сформировать требования и создать дизайн.
Вы не можете сделать их идеальными, но их важность для эффективного создания хорошего программного обеспечения не следует упускать из виду.
Выявление требований требует активного изучения видения клиента, задавая вопросы о проблемах, которые клиент, возможно, не рассмотрел.
Помимо выявления конкретных потребностей, нужно спрашивать о возможных компромиссах, которые клиент может принять в решении.
С четким представлением о том, что вы пытаетесь выполнить, далее вы можете обратиться к шаблонам дизайна и диаграммам.
Рассмотрим следующий сценарий.
Вас наняли, чтобы спроектировать дом.
Прежде чем приступить к закладке фундамента, вы должны сначала понять, чего хочет домовладелец.
Эта отправная точка известна как выявление требований.
Домовладелец хочет иметь тренажерный зал, санузел, три спальни и гостиную.
Выявление требований подразумевает не только выслушивание того, что говорит вам клиент, но и задавание вопросов для выяснения того, что клиент вам не сказал.
Например, это показалось вам странным, что в этом доме нет кухни?
Это было бы естественным вопросом.
Или все комнаты должны быть одинакового размера?
Насколько большой должен быть дом в целом?
И так далее.
После ответа на эти вопросы у вас теперь есть первоначальный набор требований, позволяющий начать думать о возможных проектах.
Проектная деятельность предполагает принятие требований и определение решения.
Эта деятельность включает в себя создание концептуального дизайна, а затем технического дизайна, что приводит к двум соответствующим видам артефактов, концептуальным макетам и техническим схемам.
Концептуальные макеты представляют то, как будут удовлетворены требования в целом.
На этом этапе вы фокусируетесь на дизайне дома, определяя основные компоненты и их соединения и откладывая технические детали.
И чем яснее концептуальный дизайн, тем лучше будут технические проекты.
После того, как концептуальные макеты завершены, настало время определить технические детали решения.
Из концептуального дизайна вы знаете все основные компоненты и их соединения и обязанности компонентов.
Описание того, как выполняются эти обязанности, является целью технического проектирования.
В техническом дизайне вы начинаете указывать технические детали каждого компонента.
Это делается путем разделения компонентов на более мелкие компоненты, которые достаточно специфичны для детального проектирования.
Например, компонент тренажерного зала потребует дополнительных компонентов, таких как пол.
Пол будет отвечать за поддержание большого веса.
Домовладелец тренируется как олимпийский атлет.
Разбивая компоненты все больше и больше на дополнительные компоненты, каждый из которых несет определенные обязанности, вы доходите до уровня, где вы можете сделать детальный дизайн конкретного компонента, например, описать, как укрепить пол.
Технические диаграммы выражают, как решать конкретные проблемы, подобные этой.
И при создании приемлемого решения могут возникнуть компромиссы.
Что делать, если укрепление пола в спортзале требует помещения колонн или балок в подвал под тренажерный зал?
И что, если домовладелец также хочет иметь широкое открытое пространство в подвале с хорошей комнатой отдыха?
Иногда могут возникать такие конфликты.
Вам и домовладельцу необходимо будет выработать компромисс в решении.
Если компоненты, их соединения и их обязанности в вашем концептуальном дизайне оказались невозможными в техническом дизайне, или не в состоянии удовлетворить требованиям, вам нужно будет вернуться к вашему концептуальному дизайну и переделать его.
Затем технические диаграммы становятся основой для построения предполагаемого решения.
Компоненты, когда они достаточно проработаны, превращаются в коллекции функций, классов или других компонентов.
Эти части представляют собой гораздо более простую проблему, которую разработчики могут реализовывать индивидуально.
Когда вы разделяете объекты на более мелкие объекты, вы можете обнаружить, что вы будете идентифицировать разные типы объектов.
И обычно определяют три категории объектов.
Во-первых, это Entity объекты.
Entity объекты наиболее знакомы, потому что они соответствуют некоторому реальному объекту.
Если у вас есть объект, представляющий стул в вашем программном обеспечении, то это Entity объект.
Если у вас есть объект, представляющий здание или клиента, это все Entity объекты или сущности.
Как правило, эти объекты знают свои атрибуты.
Они также смогут модифицировать себя и иметь для этого некоторые правила.
Когда вы идентифицируете объекты для включения в ваше программное обеспечение и разбиваете эти объекты на более мелкие объекты, вы сначала получаете Entity объекты.
Другие категории объектов приходят позже, когда вы начнете думать о техническом дизайне программного обеспечения.
Далее, это Boundary объекты.
Граничные объекты Boundary – это объекты, которые находятся на границе между системами.
Это может быть объект, который соприкасается с другой программной системой, например, объект, который получает информацию из Интернета.
Он также может быть объектом, который несет ответственность за отображение информации пользователю и получение его ввода.
Если вы программируете пользовательский интерфейс – визуальный аспект программного обеспечения – вы, в основном, работаете с граничными объектами.
Любой объект, который имеет дело с другой системой – пользователем, другой программной системой, Интернетом, – можно считать граничным объектом.
Далее, это объекты управления Control.
Control объектами являются объекты, которые отвечают за координацию.
Вы обнаружите объекты управления при попытке деления большого объекта и обнаружите, что было бы полезно иметь объект, который управляет другими объектами.
Организация программного обеспечения с помощью объектов сущностей, граничных объектов и объектов управления позволяет коду быть более гибким, многоразовым и поддерживаемым.
Для программного обеспечения существуют два типа требований.
Это функциональные требования, которые описывают, что система или приложение должны делать.
Например, мультимедийное приложение имеет функциональное требование о возможности загрузки полноразмерного фильма.
Естественно, что разработка программного обеспечения должна четко определять решение для удовлетворения таких требований.
Кроме функциональных требований, есть также нефункциональные требования, которые определяют, насколько хорошо система или приложение делают то, что она делает.
Такие требования могут описывать, насколько хорошо программное обеспечение работает в определенных ситуациях.
Например, мультимедийное приложение может иметь нефункциональные требования для загрузки полноразмерного фильма с определенной скоростью и для воспроизведения такого фильма в пределах определенного размера памяти.
И для решения важны как функциональные, так и нефункциональные требования.
Другой тип нефункциональных требований касается того, насколько хорошо может развиваться код программного обеспечения.
Например, части реализации, возможно, придется поддерживать использование в других подобных программных продуктах.
Кроме того, реализация может потребовать изменения в будущем.
Таким образом, другие качества, которым должно удовлетворять программное обеспечение, могут включать в себя повторное использование, гибкость и ремонтопригодность.
По мере того, как дизайн детализируется и создается реализация, требуемое качество должно проверяться с помощью таких методов, как пересмотры и тесты.
Кроме того, некоторые качества могут быть проверены с помощью обратной связью конечных пользователей.
При разработке программного обеспечения отправной точкой является то, что ваша программная структура должна соответствовать балансу желаемых качеств.
В частности, существует общий компромисс между производительностью и ремонтопригодностью.
Высокопроизводительный код может быть менее понятным и менее модульным, что делает его менее удобным.
Другим компромиссом является безопасность и производительность.
И дополнительные накладные расходы для высокой безопасности могут снизить производительность. И также дополнительный код для обратной совместимости может ухудшить производительность и ремонтопригодность.
При планировании какого-либо выступления часто используются карточки заметок.
Карточки заметок помогают вам двигаться логически из одной точки разговора в другую.
Было бы неплохо, если бы у нас было что-то похожее, чтобы логически составлять структуру программного обеспечения при формировании его дизайна.
Вы определяете компоненты, соединения и обязанности по некоторым требованиям при формировании концептуального дизайна. Здесь вы формируете свои первоначальные мысли о том, как вы можете удовлетворить требования.
В техническом дизайне эти компоненты и соединения дополнительно уточняются, чтобы придать им технические детали. Это упрощает их реализацию.
Хотя идентификация компонентов, их обязанностей и связей является хорошим первым шагом в разработке программного обеспечения, мы пока не продемонстрировали способ их представления.
И такой метод есть – это использование карточек CRC, где CRC обозначает класс, ответственность, сотрудничество.
Карты CRC помогают организовывать компоненты в классы, определять их обязанности и определять, как они будут сотрудничать друг с другом.
Рассмотрим, например, банкомат.
Вы вставляете свою банковскую карточку в банкомат, и банкомат просит вас ввести PIN-код, удостоверяющий личность для доступа.
После этого вы можете выбрать положить или снять деньги, или проверить свои остатки.
Этот сценарий определяет основные требования к системе.
Это неполный набор требований, но это хороший старт.
Помните, что требования часто являются неполными и дополняются при дальнейшем взаимодействии с вашим клиентом и конечными пользователями.
Следующим шагом будет разработка банкомата.
Но так как мы формируем концептуальный дизайн, ограничиваясь только идентификацией компонентов, их обязанностей и связей, мы можем представить компоненты с помощью нашей новой техники – карт CRC.
И карты CRC используются для записи, упорядочивания и улучшения компонентов в дизайне.
Карта CRC состоит из трех разделов.
В верхней части карты есть имя класса.
Слева – обязанности класса, а справа – список коллабораторов.
Коллабораторы – это другие классы, с которыми класс взаимодействует, чтобы выполнять свои обязанности.
Чтобы отслеживать каждый компонент и его обязанности с помощью CRC-карты, вы помещаете имя компонента в раздел имени класса и обязанности в разделе обязанностей.
До сих пор это довольно просто.
Но как насчет связей?
В разделе «Коллабораторы» вы перечисляете другие компоненты, к которым ваш текущий компонент подключается или взаимодействует, чтобы выполнять свои обязанности.
И карты CRC сами по себе небольшие, поэтому вы не можете много писать в них.
Это заставляет вас продолжать разбивать каждый компонент на более мелкие компоненты и, в конечном итоге, классы, которые достаточно малы для индивидуального описания.
Теперь, когда мы узнали о CRC-картах, давайте использовать их для разработки нашей банковской системы.
Начнем с базового пользовательского компонента.
В этом примере нашим основным пользователем будет клиент банка.
Мы размещаем клиентов банка в разделе имени класса.
Обязанности банковского клиента включают ввод банковской карточки или выбор операции, такой как депозит, снятие или проверка остатка на счете.
Перечислим их в разделе ответственности CRC-карты.
И мы поместим банкомат в разделе Коллабораторы.
Тоже самое мы можем сделать для банкомата.
И с нашими картами CRC мы можем объединить вместе компоненты для совместной работы.
Например, положите карту клиента CRC слева и карточку CRC банкомата справа.
Когда карты CRC организованы, вы можете имитировать прототип системы.
Теперь, вы можете заметь, что сам банкомат содержит несколько разных компонентов, которые могут быть отдельными классами для программирования.
Например, есть кард-ридер, клавиатура, дисплей и так далее.
Каждый из этих классов, их обязанности и коллабораторы могут быть описаны на их собственных картах.
При встрече с командой разработчиков программного обеспечения вы можете разложить все карты на столе и обсуждать моделирование того, как эти классы работают с другими классами для выполнения своих обязанностей.
И эти симуляции могут выявлять недостатки в дизайне, и вы можете экспериментировать с альтернативами, вводя соответствующие карты.