Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ПР12. Class diagram.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
337.41 Кб
Скачать

стр. 8 из 8

Практическая работа №12 Диаграмма классов.

Практическая работа №12. Диаграмма классов

Цель: Изучение объектно-ориентированного подхода к проектированию приложений.

Задача: Следуя принципам объектно-ориентированного подхода, спроектировать иерархию DOM и построить диаграмму классов.

Теоретическая часть.

Основные сведения о базовых элементах диаграммы классов и связях между ними см. лекцию «Диаграмма классов».

Этапы объектно-ориентированного подхода к разработке ПО:

Объектно-ориентированный анализ (analysis) - способ анализа, изучающий требования к системе с точки зрения будущих классов и объектов, основываясь на словаре предметной области.

Объектно-ориентированное проектирование (design) - способ проектирования, включающий в себя описание процесса объектно-ориентированной декомпозиции и объектно-ориентированную нотацию для описания различных моделей системы (логической и физической, статической и динамической).

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

Порядок их применения таков: сначала проводится объектно-ориентированный анализ, затем проектирование, а после этого - реализация (то есть программирование).

Цели проведения анализа

  • A1 Понять проблему или проблемы, которые программная (или иная) система должна решить.

  • A2 Задать значимые вопросы о проблеме и о системе.

  • A3 Обеспечить основу для ответов на вопросы о специфических свойствах проблемы и системы.

  • A4 Определить, что система должна делать.

  • A5 Определить, что система не должна делать.

  • A6 Убедиться, что система удовлетворит потребности ее пользователей и определить критерии ее приемки. Это особенно важно, когда система разработана по контракту для внешнего клиента.

  • A7 Обеспечить основу для разработки системы

Подход к проектированию программ в целом

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

Объектно-ориентированное проектирование основывается на описании структуры и поведения проектируемой системы, то есть, фактически, в ответе на два основных вопроса:

  • Из каких частей состоит система.

  • В чём состоит ответственность каждой из частей.

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

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

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

Рекомендации:

30 Принципов объектно-ориентированного дизайна

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

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

  3. Помните принцип «Разделяй и властвуй». Если проблема, которой вы занимаетесь, слишком сложна, попробуйте вообразить, как должна работать программа, если некий черный ящик скроет все сложности. Этот черный ящик — объект. Напишите сначала код, который использует объект, а потом рассмотрите проблемный объект еще раз и инкапсулируйте его сложности в другие объекты.

  4. Отделите создателя класса, от его пользователя (программиста-клиента). Пользователь класса — это своего рода «покупатель», и ему не интересно, что происходит внутри класса. Создатель класса должен быть экспертом в своем деле и создавать код так, чтобы даже использование его начинающим программистом, было работоспособным и эффективным. Библиотеку использовать легко, только если способ ее использования прозрачен.

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

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

  7. Все проблемы разработки ПО могут быть упрощены добавлением дополнительного уровня концептуального обобщения. Это фундаментальное правило разработки ПО является основой абстракции, наиважнейшей особенности объектно-ориентированного программирования.

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

  9. Делайте классы настолько атомарными, насколько это возможно. Давайте каждому классу единственное, четкое предназначение. Если ваши классы или вся система становятся слишком сложными, разбейте сложные классы на более простые. Самый простой индикатор — размер, если класс слишком большой, есть вероятность, что он делает слишком много и должен быть декомпозирован. Ключом к переработке класса может быть:

    • Сложный switch(оператор выбора): попробуйте использовать полиморфизм.

    • Большое количество методов, охватывающих очень разные типы операций: следует использовать несколько классов.

    • Большое количество переменных-членов класса, которые определяют очень разные параметры: следует использовать несколько классов.

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

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

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

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

  14. Меньшее — это большее. Начните с минимального интерфейса класса, настолько маленького и простого, насколько вообще позволяет решение текущей задачи. Не пытайтесь предвидеть все способы, которыми ваш класс может быть использован. Напротив, используя класс, вы обнаружите, как еще стоит расширить интерфейс. Однако, если класс уже используется, невозможно расширить интерфейс без изменения клиентского кода. Если нужно добавить новые методы — клиентский код не изменится. Но если новые методы заменят функциональность старых, лучше оставить старый интерфейс (вы можете объединить функциональность в последующей реализации, если захотите). Если нужно расширить интерфейс существующего метода добавлением новых аргументов, создайте перегруженный метод с новыми аргументами. Такой способ никак не помешает существующим вызовам того метода.

  15. Прочтите ваши классы вслух, чтобы убедиться, что они логичны. Отношение между производным и базовым классом произносите как «есть», а между классом и объектами-членами как «имеет, содержит».

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

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

  18. Следите за перегрузкой. Метод не должен исполнять код условно в зависимости от типа значения аргумента. В этом случае следует создать два или более перегруженных метода взамен.

  19. Иногда помогает простая агрегация. Система комфорта пассажиров на авиалиниях состоит из разрозненных элементов: сидения, кондиционера, видео и т.п., и таких комплектов в самолете много. Вы создали частные (private) члены класса и построили полностью новый интерфейс? Не в этом случае. Компоненты так же являются частью открытого интерфейса, так что необходимо создавать открытые (public) члены класса. Такие объекты имеют собственные частные реализации, которые по прежнему безопасны. Простую агрегацию не следует применять часто, но иногда без нее не обойтись.

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

  21. Остерегайтесь «синдрома гигантских объектов». Это частый недуг процедурных программистов, которым в новинку ООП и которые создают процедурную программу, и запирают ее в один-два гигантских объекта. За исключением каркаса приложения, объекты представляют концепцию заложенную в ваше приложение, а не его элементы.

  22. Если надо сделать что-нибудь непереносимое, создайте абстракцию для этой задачи и локализуйте ее в классе. Этот дополнительный уровень абстракции предотвратит распространение непереносимости по программе. Эта идиома заложена в шаблон проектирования «Мост»

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

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

  25. Используйте наследование и перекрытие методов для выражения разницы в поведении и поля для выражения различий состояний. Предельный пример того, чего не следует делать — это наследование различных классов для определения цветов вместо использования поля «цвет».

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

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

  28. Используйте шаблоны проектирования для уничтожения «голой функциональности». То есть, если только один объект вашего класса должен быть создан, вставляйте код в приложение с комментарием «сделать только раз». Оберните его в шаблон «Одиночку». Если у вас много беспорядочного кода, который создает ваши объекты, в главной программе, поищите созидательный шаблон, вроде «фабричного метода», в который вы сможете инкапсулировать создание объектов. Устранение «голой функциональности» не только сделает код гораздо более понятным и поддерживаемым, кроме того оно защитит его от «благих намерений» тех, кто будет заниматься его поддержкой после вас.

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

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

Задание: Спроектировать DOM и построить диаграмму классов для слоя бизнес-логики «информационной системы текущей успеваемости учащихся». Общее описание: Система выводит текущие оценки выбранного учащегося по выбранному предмету и вычисляет средний балл. Оценки вносит преподаватель, читающий указанный предмет.

  1. Основное задание:

    1. Составить перечень классов объектной модели предметной области.

    2. Определить отношения между классами.

    3. Определить возможные состояния (список атрибутов) классов.

    4. Определить поведение (список методов) классов.

    5. На основе диаграммы классов предметной области построить диаграмму реализации (диаграмму классов с указанием полей и методов).

    6. Дать оценку модели с точки зрения соответствия основным принципам проектирования.

  2. Дополнительные задания:

    1. Создать каркас кода для полученной модели на языке С++.

    2. Создать модель хранения данных (если необходимо) для построенной DOM.

    3. Описать пример класса Data-mapper для слоя ORM между моделью хранения данных и DOM.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]