Основы объектно- ориентированного программирования Преподаватель: Шамшев Анатолий Борисович ICQ: 446849975 Блог: anshamshev.wordpress.com 1 Основы объектно.

Презентация:



Advertisements
Похожие презентации
Тема 5 Модели данных в нотации UML 1.Понятие UML 2.Классы, атрибуты и операции 3.Категории связей. Связь-зависимость 4.Связи-обобщения и механизм наследования.
Advertisements

Исключительные ситуации. Схема обработки исключений Try { //охраняемый блок trow (new MyException();) } catch(MyExeption e) { … } catch(Exeption e){ …
Методология объектно- ориентированного программирования.
OOП Инна Исаева. Подпрограмма – это большая программа, разделённая на меньшие части. В программе одна из подпрограмм является главной. Её задача состоит.
Унифицированный язык моделирования UML является графическим языком для визуализации, конструирования и документирования систем, в которых большая роль.
Основы информатики Классы Заикин Олег Сергеевич zaikin.all24.org
Теория экономических информационных систем Семантические модели данных.
Полиморфизм. Полиморфизм – это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.
Наследование Наследование – это отношение является между классами. class Person { string first_name; int birth_year;... } class Student : Person { float.
Практическое занятие 6. Функции. Большинство языков программирования используют понятия функции и процедуры. C++ формально не поддерживает понятие процедуры,
Языки и методы программирования Преподаватель – доцент каф. ИТиМПИ Кузнецова Е.М. Лекция 7.
Лекция 5 Способы конструирования программ. Основы доказательства правильности.
WORK WITH UML Универсальный язык моделирования (UML) Studybook for students Author Dudnik Oxana.
Разработка объектно- ориентированного ПО Итеративная модель разработки (развитие водопадной модели) анализ проектирование кодирование тестирование.
Универсальность. Классы с родовыми параметрами. Под универсальностью (genericity) понимается способность класса объявлять используемые им типы как параметры.
1 Диаграммы реализации (implementation diagrams).
Реляционная модель – это особый метод рассмотрения данных, содержащий данные в виде таблиц, способов работы и манипуляции с ними в виде связей. структура,
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ СТАВРОПОЛЬСКИЙ ГОСУДАРСТВЕННЫЙ АГРАРНЫЙ УНИВЕРСИТЕТ.
8. Моделирование логической структуры системы Диаграмма классов Диаграмма классов служит для моделирования классов и отношений между ними.
Диаграммы UML Диаграмма классов (Class Diagram). Основные вопросы Что такое диаграмма классов Компоненты диаграммы классов и их назначение Пример диаграммы.
Транксрипт:

Основы объектно- ориентированного программирования Преподаватель: Шамшев Анатолий Борисович ICQ: Блог: anshamshev.wordpress.com 1 Основы объектно - ориентированного программирования

Список литературы Бертран Мейер Объектно-ориентированное конструирование программных систем Биллиг В.А. Основы программирования на C# Интернет-университет информационных технологий - ИНТУИТ.ру, 2006 Анисимов А.Е., Пупышев В.В. Сборник заданий по основаниям программирования БИНОМ. Лаборатория знаний, Интернет-университет информационных технологий - ИНТУИТ.ру, 2006 Фридман А.Л. Язык программирования Си++ 2 Основы объектно - ориентированного программирования

Методологии программирования Машинно-ориентированное Структурное Модульное Объектно-ориентированное Компонентно-ориентированное, функциональное (перспективное) 3 Основы объектно - ориентированного программирования

Традиционные модульные структуры Подпрограммы (процедуры, функции) Пакеты – развитие подпрограмм Классы (в ОО – языках - модули)

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

Преимущества использования OO- метода Совместимость Переносимость Простота использования Эффективность: Своевременность, экономичность и функциональность

Состав объекта Поля (свойства) Методы Конструкторы, в т.ч. статические Деструкторы События Константы Операторы Основы объектно - ориентированного программирования 7

Декомпозиция Пример – иерархия нисходящего проектирования

Иерархия нисходящего проектирования

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

Модульная понятность

ОО - подход Объектная декомпозиция + 3 важнейших понятия: Инкапсуляция – объединение в одном классе данных и обрабатывающих их методов Наследование – Возможность расширения возможностей класса путём создания наследников Полиморфизм – возможность присвоения экземпляру класса экземпляров классов - наследников

Инкапсуляция и скрытие информации Разработчик каждого модуля должен выбрать некоторое подмножество свойств модуля в качестве официальной информации о модуле, доступной авторам клиентских модулей. Применение этого правила означает, что каждый модуль известен всем остальным через некоторое официальное описание, или так называемые общедоступные (public) свойства. Описание должно включать лишь некоторые из свойств модуля. Остальные свойства должны оставаться не общедоступными, или закрытыми. Вместо терминов - общедоступные и закрытые свойства - используются также термины: экспортируемые и частные (скрытые) (private) свойства. Общедоступные свойства модуля известны также как интерфейс.

Скрытие информации

Наследование Основы объектно - ориентированного программирования 15

Полиморфизм Под полиморфизмом в ООП понимают способность одного и того же программного текста x.M выполняться по- разному, в зависимости от того, с каким объектом связана сущность x. Полиморфизм гарантирует, что вызываемый метод M будет принадлежать классу объекта, связанному с сущностью x.

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

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

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

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

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

Функции и эволюция Главная функция часто не только не является наилучшим критерием для начального определения системы, но она может также в процессе эволюции системы почти сразу оказаться среди изменяемых свойств. Большие научные программы очень часто имеют две версии: одну, которая "пусть работает всю ночь, выполняя большую порцию вычислений", и другую, которая "позволяет мне сначала проверить некоторые вещи, посмотреть на результаты, а затем вычислить еще что-нибудь". Подход сверху вниз не способен учесть то обстоятельство, что результирующие программы должны быть ничем иным как двумя версиями одной и той же программной системы, независимо от того, как они проектируются - одновременно или одна выводится из другой. Два самых неприятных последствия подхода сверху вниз: во-первых, он сосредотачивается на внешнем интерфейсе, во-вторых, он преждевременно устанавливает временные отношения. Архитектура системы должна основываться на содержании, а не на форме. Упор на внешний интерфейс неизбежен для метода, ключевой вопрос которого: "Что система будет делать для конечного пользователя?».

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

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

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

Основные вопросы Как находить релевантные типы объектов? Как описывать типы объектов? Как описывать взаимоотношения типов объектов и их близость? Как использовать типы объектов для структурирования ПО?

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

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

Описание отношений Отношение "быть клиентом" достаточно широкое и покрывает многие виды зависимостей. Примерами таких зависимостей является отношение, часто называемое агрегацией (присутствие в каждом объекте типа B подобъекта типа A ), а также зависимость по ссылке и родовая зависимость. Отношение наследования покрывает многочисленные формы специализации. Многие зависимости можно выразить в общем виде другими способами. Например, для описания зависимости "от 1-го до n" (каждый объект типа B связан с не менее чем одним и не более чем с n объектами типа A) указывается, что B является клиентом A, и присоединяется инвариант класса, точно определяющий природу отношения "быть клиентом". Так как инварианты классов выражаются с помощью логического языка, они покрывают намного больше различных отношений, чем может предложить подход сущность-связь или другие аналогичные подходы.

Ключевые концепции Вычисление включает три вида ингредиентов: процессоры (или потоки управления), действия (или функции) и данные (или объекты). Архитектуру системы можно получить исходя из функций или из типов объектов. Описание, основанное на типах объектов, с течением времени обеспечивает лучшую устойчивость и лучшие возможности для повторного использования, чем описание, основанное на анализе функций системы. Как правило, неестественно считать, что задача системы состоит в реализации только одной функции. У реальной системы обычно имеется не одна "вершина" и ее лучше описывать как систему, предоставляющую множество услуг. На ранних стадиях проектирования и разработки системы не нужно уделять много внимания ограничениям на порядок действий. Многие временные соотношения могут быть описаны более абстрактно в виде логических ограничений. Функциональное проектирование сверху вниз не подходит для программных систем с долгим жизненным циклом, включающим их изменения и повторное использование. При ОО-конструировании ПО структура системы основывается на типах объектов, с которыми она работает. При ОО-разработке первоначальный вопрос не в том, что система делает, а в том, с какими типами объектов она это делает. Решение о том, какая функция является самой верхней функцией системы (и имеется ли таковая), откладывается на последние этапы процесса проектирования. Чтобы проектируемое ПО было расширяемым и допускало повторное использование, ОО- конструирование должно выводить архитектуру из достаточно абстрактных описаний объектов. Между типами объектов могут существовать два вида отношений: "быть клиентом" и наследование.

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

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

Различные представления

Опасность излишней спецификации Результаты изучения Линцем (Lientz) и Свенсоном (Swanson) стоимости сопровождения показали, что более 17% стоимости ПО приходится на изменения в форматах данных. Очевидно, что метод, который ставит анализ и проектирование в зависимость от физического представления структур данных, не обеспечит разработку достаточно гибкого ПО. Поэтому при использовании объектов или типов объектов в качестве основы для архитектуры системы требуется найти лучший способ описания, чем конкретное представление.

Абстрактный взгляд на стек Представления стека при всех их различиях объединяет то, что они описывают структуру "хранения», к которой применяются определенные операции, обладающие определенными свойствами. Сосредоточившись не на выборе конкретного представления структуры, а на этих операциях и свойствах, можно получить достаточно абстрактное, но, тем не менее, полезное описание понятия стек. Обычно для стеков рассматриваются следующие операции: Команда вталкивания некоторого элемента на вершину стека - put. Команда удаления верхнего элемента стека - remove. Запрос элемента, находящегося на вершине стека (если стек не пуст) - item. Запрос на проверку пустоты стека. Кроме того, понадобится операция-конструктор для создания пустого стека - make.

Формализация спецификаций Спецификация АТД предоставит эту информацию. Она состоит из четырех разделов, разъясняемых в следующих разделах: ТИПЫ - указываются специфицируемые типы - STACK[G]. ФУНКЦИИ - перечисляются операции, применяемые к экземплярам данного АТД. – функция-конструктор моделирует операцию, создающую экземпляры T из экземпляров других типов или вообще не использующую аргументов. – функции-запросы моделируют операции, которые устанавливают свойства T, выраженные в терминах экземпляров других типов. – функции-команды моделируют операции, которые по существующим экземплярам T и экземплярам других типов выдают новые экземпляры типа T. АКСИОМЫ – свойства объектов ПРЕДУСЛОВИЯ – условия, необходимые для работы функций – запросов и функций - команд

Полная спецификация стека

Построение классов на основе АТД Класс - это абстрактный тип данных, снабженный некоторой (возможно частичной) реализацией Полностью реализованный класс называется эффективным (effective). Класс, который реализован лишь частично или совсем не реализован, называется отложенным (deferred). Всякий класс является либо отложенным, либо эффективным. Компоненты эффективного класса: – Спецификации АТД. – Выбора представления. – Реализация множества функций в при помощи средств представления в виде множества механизмов (или компонентов (features)), каждый из которых реализует одну из функций в терминах представления и при этом удовлетворяет аксиомам и предусловиям.

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

АТД и сокрытие информации

Классы и объекты Класс - это абстрактный тип данных, поставляемый с возможно частичной реализацией. Абстрактные типы данных (АТД) являются математическим понятием, пригодным на этапе подготовки спецификации - в процессе анализа. Понятие класса, предусматривая частичную или полную реализацию, обеспечивает необходимую связь с разработкой ПО на этапах проектирования и программирования. Напомним, класс называется эффективным, если его реализация полна, и отложенным - при частичной реализации. Аналогично АТД, класс - это тип, описывающий множество возможных структур данных, называемых экземплярами (instances) класса. Экземпляры АТД являются абстракциями - элементами математического множества. Экземпляр класса конкретен - это структура данных, размещаемая в памяти компьютера и обрабатываемая программой. Термин "объект" появляется как побочный продукт определения "класса". Объект это просто экземпляр некоторого класса. Программные тексты, описывающие создаваемую систему, содержат определения классов. Объекты создаются только в процессе выполнения программ.

Роль классов Модули - это структурные единицы, из которых состоит программа. Независимо от конкретного выбора той или иной модульной структуры, модуль всегда рассматривается как синтаксическая концепция. Тип является статическим описанием вполне определенных динамических объектов - элементов данных, которые обрабатываются во время выполнения программной системы. Набор типов обычно содержит предопределенные типы, такие как INTEGER или CHARACTER, а также пользовательские типы: записи (структуры), указатели, множества (в Pascal), массивы и другие. Понятие типа является семантической концепцией, и каждый тип непосредственно влияет на выполнение программной системы, так как описывает форму объектов, которые система создает и которыми она манипулирует. Класс как модуль и как тип Мощь ОО-метода, во многом, следствие этого отождествления. Наследование, в частности, может быть полностью понято только при рассмотрении его, как модульного расширения, так и, одновременно, уточнения специализации типа.

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

Простой класс: точка на плоскости /// /// Абстрактное представление точки /// public abstract class AbstractPoint { public int x, y;//Координаты на плоскости abstract public void Draw();//Рисование точки public abstract double Distance(Point p1);//Расстояние до другой точки }

Просто точка public class Point:AbstractPoint { public Point() { } public Point(int x1,int y1) { x = x1; y = y1; } override public void Draw() { Console.WriteLine("Рисование точки"); } public override double Distance(Point p1) { return (Math.Sqrt((x - p1.x)*(x - p1.x) + (y - p1.y)*(y - p1.y))); }

Наследник точки - линия public class Line:Point { public Line() { } public Line (int xstart, int ystart, int xend, int yend) { x = xstart; y = ystart; x1 = xend; y1 = yend; } public int x1, y1; private double GetLength() { return Math.Sqrt((x - x1)*(x - x1) + (y - y1)*(y - y1)); } public double Length { get { return GetLength();} } override public void Draw() { Console.WriteLine("Рисование линии"); } public override double Distance(Point p1) { return base.Distance(p1); }

Использование созданных типов namespace ConsoleApplication3 { class Program { static void Main(string[] args) { Point t = new Point(); t.Draw(); t = new Line(); t.Draw(); Console.ReadKey(); }

Результат выполнения программы

Управление памятью Создание нового экземпляра – оператор new Выделение памяти – область памяти, называемая «кучей» (heap) Динамический режим выделения памяти

Преимущества: Простота, эффективность Возможность переназначения выделенной памяти Недостатки: Необходимость следить за освобождением памяти Появление неиспользуемых объектов Появление недостижимых объектов

Манипулирование памятью Выделение памяти – оператор new Освобождение памяти – Pascal – оператор Dispose; C# - автоматический сборщик мусора – System.GC; в отдельных случаях реализация в классе метода Dispose

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

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

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

Свойства ОО-подхода Декомпозиции (decomposability). Композиции (composability). Понятности (understandability). Непрерывности (continuity). Защищенности (protection).

Декомпозиция

Иерархия нисходящего проектирования

Модульная композиция

Модульная понятность

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

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

Правила ОО-подхода Прямое отображение (Direct Mapping). Минимум интерфейсов (Few Interfaces). Слабая связность интерфейсов (Small interfaces - weak coupling). Явные интерфейсы (Explicit Interfaces). Скрытие информации (инкапсуляция) (Information Hiding).

Прямое отображение Модульная структура, создаваемая в процессе конструирования ПО, должна оставаться совместимой с модульной структурой, создаваемой в процессе моделирования проблемной области.

Минимум интерфейсов

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

Явные интерфейсы Всякое общение двух модулей A и B между собой должно быть очевидным и отражаться в тексте A и/или B.

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

Скрытие информации

Принципы ОО-подхода Принцип Лингвистических Модульных Единиц (Linguistic Modular Units). Принцип Самодокументирования (Self- Documentation). Принцип Унифицированного Доступа (Uniform Access). Принцип Открыт-Закрыт (Open-Closed). Принцип Единственного выбора (Single Choice).

Лингвистические модульные единицы Модули должны соответствовать синтаксическим единицам используемого языка. Упомянутым выше языком может быть язык программирования, язык проектирования, язык оформления технических требований и т. д. В случае языка программирования модули должны независимо компилироваться. Этот принцип на любом уровне (анализа, проектирования, реализации) не допускает объединения метода, исходящего из концепции модульности, и языка, не содержащего соответствующих модульных конструкций. Непрерывность: если границы модуля в окончательном тексте программы не соответствуют логической декомпозиции спецификации или проекта, то при сопровождении системы и ее эволюции будет затруднительно или даже невозможно поддерживать совместимость различных уровней. Прямое отображение: необходимо поддерживать явное соответствие между структурой модели и структурой решения. Декомпозиция: для разбиения системы на отдельные задачи необходимо быть уверенным, что результатом решения каждой из задач явится четко ограниченная синтаксическая единица; Композиция: что же, кроме модулей с однозначно определенными синтаксическими границами, можно объединять между собой? Защищенность: лишь в случае, если модули синтаксически разграничены, можно надеяться на возможность контроля области действия ошибок.

Самодокументируемость Разработчик модуля должен стремиться к тому, чтобы вся информация о модуле содержалась в самом модуле.

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

Унифицированный доступ

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

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

Принцип единственного выбора type PUBLICATION = record author, title: STRING; publication_year: INTEGER case pubtype:(book, journal, conference_proceedings) of book:(publisher: STRING); journal:(volume, issue: STRING); proceedings:(editor, place: STRING) end

Повторное использование Преимущества: Своевременность. При использовании уже существующих компонентов нужно меньше разрабатывать, а, следовательно, ПО создается быстрее. Сокращение объема работ по сопровождению ПО. Если кто-то разработал ПО, то он же отвечает и за его последующее развитие. Надежность. Получая компоненты от поставщика с хорошей репутацией, вы имеете определенную гарантию, что разработчики предприняли все нужные меры, включая всестороннее тестирование и другие методы контроля качества. В большинстве случаев можно ожидать, что кто-то уже испытал эти компоненты до вас и обнаружил все возможно остававшиеся ошибки. Эффективность. Факторы, способствующие возможности повторного использования ПО, побуждают разработчиков компонентов пользоваться наилучшими алгоритмами и структурами данных, известными в их конкретной сфере деятельности. При разработке большого проекта невозможно оптимизировать все его детали. Следует стремиться к достижению наилучших решений в своей области знаний, а в остальном использовать профессиональные разработки. Совместимость. Если использовать хорошую современную ОО-библиотеку, то ее стиль повлияет, за счет естественного "процесса диффузии", на стиль разработки всего ПО. Инвестирование. Создание повторно используемого ПО позволяет сберечь плоды знаний и открытий лучших разработчиков, превращая временные ресурсы в постоянные.

Ресурсы, используемые повторно Персонал Проекты и спецификации Образцы проектов (шаблоны) Исходный текст Абстрактные модули

Трудности повторного использования Придумано не нами (Not Invented Here или "NIH") Привычка препятствовать нововведениям (Habit Inhibiting Novelty или "HIN") Повторно использовать или переделать?

Форматы распространения для повторного использования Краткая форма – описание интерфейса + исполняемый код Полная форма (суперпоставка) – полный набор документации + исходный код + исполняемый код

Требования к модульным структурам Изменчивость Типов (Type Variation) - Повторно используемый модуль поиска должен быть применим ко многим различным типам элементов без того чтобы пользователи вынуждены были производить "вручную" изменения в тексте программы.. Группирование Подпрограмм (Routine Grouping) -. Самодостаточный, повторно используемый модуль должен включать множество подпрограмм, обеспечивающих каждую из необходимых операций. Изменчивость Реализаций (Implementation Variation) – Один модуль не может охватить все возможные варианты реализации – поддержка идеи семейства модулей. Независимость Представлений (Representation Independence) - Общая структура повторно используемого модуля должна позволять определять действия при отсутствии сведений о реализации модуля. Факторизация Общего Поведения (Factoring Out Common Behaviors) – Общие действия выполняются одиним и тем же способом вне зависимости от внутренней реализации.

Традиционные модульные структуры Подпрограммы (процедуры, функции) Пакеты – развитие подпрограмм Классы (в ОО – языках - модули)

Перегрузка и универсальность Два технических приема - перегрузка (overloading) и универсальность (genericity) предлагают свои решения, направленные на достижение большей гибкости модулей. Перегрузка - это связывание с одним именем более одного содержания: перегрузка методов, перегрузка операторов. square (x: INTEGER): INTEGER square (x: REAL): REAL square (x: DOUBLE): DOUBLE

Универсальность Универсальность - это механизм определения параметризованных шаблонов модулей (module patterns), параметры которых представляют собой типы. List Имя G, представляющее произвольный тип, и называется формальным родовым параметром (formal generic parameter). List, List, List Универсальность позволяет использовать тот же текст, реализующий некоторое понятие, для различных видов объектов

Процесс разработки программной системы

Стек /// /// Абстрактный класс GenStack задает контейнер с /// доступом LIFO: /// Функции: /// конструктор new: -> GenStack /// запросы: /// item: GenStack -> T /// empty: GenStack -> Boolean /// процедуры: /// put: GenStack*T -> GenStack /// remove: GenStack -> GenStack /// Аксиомы: /// remove(put(s,x)) = s /// item(put(s,x)) = x /// empty(new)= true /// empty(put(s,x)) = false /// abstract public class GenStack { /// /// require: not empty(); /// /// элемент вершины(последний пришедший) abstract public T item(); /// /// require: not empty(); /// ensure: удален элемент вершины(последний пришедший) /// abstract public void remove(); /// /// require: true; ensure: elem находится в вершине стека /// abstract public void put(T t); /// /// require: true; /// /// true если стек пуст, иначе false abstract public bool empty(); }// class GenStack

Односвязанный стек /// /// Стек, построенный на односвязных элементах списка GenLinkable /// public class OneLinkStack : GenStack { public OneLinkStack() { last = null; } private GenLinkable last; //ссылка на стек (вершину стека) public override T item() { return (last.Item); } //item public override bool empty() { return (last == null); } //empty public override void put(T elem) { GenLinkable newitem = new GenLinkable (); newitem.Item = elem; newitem.Next = last; last = newitem; } //put public override void remove() { last = last.Next; } //remove } //class OneLinkStack

Класс Linkable public class GenLinkable { public T Item; public GenLinkable Next; public GenLinkable() { Item = default(T); Next = null; }

Стек на основе массива public class ArrayUpStack : GenStack { private int SizeOfStack; private T[] stack; private int top; /// /// конструктор /// /// размер стека public ArrayUpStack(int size) { SizeOfStack = size; stack = new T[SizeOfStack]; top = 0; } /// /// require: (top < SizeOfStack) /// /// элемент, помещаемый в стек public override void put(T x) { stack[top] = x; top++; } public override void remove() { top--; } public override T item() { return stack[top - 1]; } public override bool empty() { return (top == 0); } } //class ArrayUpStack

public void TestStacks() { OneLinkStack stack1 = new OneLinkStack (); OneLinkStack stack2 = new OneLinkStack (); ArrayUpStack stack3 = new ArrayUpStack (10); stack1.put(11); stack1.put(22); int x1 = stack1.item(), x2 = stack1.item(); if ((x1 == x2) && (x1 == 22)) Console.WriteLine("OK!"); stack1.remove(); x2 = stack1.item(); if ((x1 != x2) && (x2 == 11)) Console.WriteLine("OK!"); stack1.remove(); x2 = (stack1.empty()) ? 77 : stack1.item(); if ((x1 != x2) && (x2 == 77)) Console.WriteLine("OK!"); stack2.put("first"); stack2.put("second"); stack2.remove(); string s = stack2.item(); if (!stack2.empty()) Console.WriteLine(s); stack3.put(3.33); stack3.put(Math.Sqrt(Math.PI)); double res = stack3.item(); stack3.remove(); res += stack3.item(); Console.WriteLine("res= {0}", res); }

public void TestPerson() { OneLinkStack stack1 = new OneLinkStack (); OneLinkStack stack2 = new OneLinkStack (); ArrayUpStack stack3 = new ArrayUpStack (10); ArrayUpStack stack4 = new ArrayUpStack (7); stack2.put("Петров"); stack2.put("Васильев"); stack2.put("Шустов"); stack1.put(27); stack1.put(45); stack1.put(53); stack3.put( ); stack3.put( ); stack3.put( ); stack4.put(new Person(stack2.item(), stack1.item(), stack3.item())); stack1.remove(); stack2.remove(); stack3.remove(); stack4.put(new Person(stack2.item(), stack1.item(), stack3.item())); stack1.remove(); stack2.remove(); stack3.remove(); stack4.put(new Person(stack2.item(), stack1.item(), stack3.item())); Person pers = stack4.item(); pers.PrintPerson(); stack4.remove(); pers = stack4.item(); pers.PrintPerson(); stack4.remove(); pers = stack4.item(); pers.PrintPerson(); stack4.remove(); if (stack4.empty()) Console.WriteLine("OK!"); }

Базовые методы обеспечения надёжности Ключевой концепцией является Проектирование по контракту (Design by Contract) - установление отношений между классом и его клиентами в виде формального соглашения, недвусмысленно устанавливающее права и обязанности сторон. Только через точное определение для каждого модуля требований и ответственности можно надеяться на достижение существенной степени доверия к большим программным системам.

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

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

Схема Бертрана обработки исключительных ситуаций Бертран Мейер предложил следующую схему обработки исключительных ситуаций. В основе ее лежит подход к проектированию программной системы на принципах Проектирования по Контракту. У обработчика исключительной ситуации только две возможности - Retry и Rescue.

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

Блок finally Освобождение ресурсов, занятых try-блоком, выполняет finally-блок. Если он присутствует, он выполняется всегда, сразу же после завершения работы try-блока, как бы последний ни завершился. Во всех случаях, прежде чем управление будет передано по предписанному назначению ( в том числе, прежде чем произойдет захват исключения), предварительно будет выполнен finally-блок, который освобождает ресурсы, занятые try-блоком, а параллельно будет происходить освобождение стека от локальных переменных.

public void Pattern() { do { try { bool Danger = false; Success = true; MakeJob(); Danger = CheckDanger(); if (Danger) throw (new MyException()); MakeLastJob(); } catch (MyException me) { if (count > maxcount) throw(new MyException("Три попытки были безуспешны")); Success = false; count++; //корректировка ситуации Console.WriteLine("Попытка исправить ситуацию!"); level += 1; } } while (!Success); }

public class MyException : Exception { public MyException() { } public MyException(string message) : base(message) { } public MyException(string message, Exception e) : base(message, e) { }

private Random rnd = new Random(); private int level = -10; private bool Success; //true - нормальное завершение private int count = 1; // число попыток выполнения private const int maxcount = 3;

private void MakeJob() { Console.WriteLine("Подготовительные работы завершены"); } private bool CheckDanger() { //проверка качества и возможности продолжения работ int low = rnd.Next(level, 10); if (low > 6) return (false); return (true); } private void MakeLastJob() { Console.WriteLine("Все работы завершены успешно"); }

public void TestPattern() { Excepts ex1 = new Excepts(); try { ex1.Pattern(); } catch (Exception e) { Console.WriteLine("исключительная ситуация при вызове Pattern"); Console.WriteLine(e.ToString()); }

Класс Exception Основными свойствами класса являются: Message; HelpLink; InnerException; Source; StackTrace; TargetSite Из методов класса отметим метод GetBaseException.

throw(new MyException("Все попытки Pattern безуспешны", me)); static public void PrintProperties(Exception e) { Console.WriteLine("Свойства исключения:"); Console.WriteLine("TargetSite = {0}", e.TargetSite); Console.WriteLine("Source = {0}", e.Source); Console.WriteLine("Message = {0}", e.Message); if (e.InnerException == null) Console.WriteLine("InnerException = null"); else Console.WriteLine("InnerException = {0}", e.InnerException.Message); Console.WriteLine("StackTrace = {0}", e.StackTrace); Console.WriteLine("GetBaseException = {0}", e.GetBaseException()); }

Цель программирования Качество - это цель инженерной деятельности; построение качественного ПО (software) - цель программной инженерии (software engineering).

Методологии программирования Машинно-ориентированное Структурное Модульное Объектно-ориентированное Компонентно-ориентированное (перспективное)

Факторы качества Внешние – Надёжность, простота использования, эффективность и т.д. Внутренние – Модульность, читаемость и т.д.

Внешние факторы Корректность (Correctness) Корректность - это способность ПО выполнять точные задачи так, как они определены их спецификацией. Устойчивость (Robustness) Устойчивость - это способность ПО соответствующим образом реагировать на аварийные ситуации.

Внешние факторы Расширяемость (Extendibility) Расширяемость - это легкость адаптации ПО к изменениям спецификации. Повторное использование (Reusability) Повторное использование есть способность элементов ПО служить для построения многих различных приложений.

Внешние факторы Совместимость (Compatibility) Совместимость - это легкость сочетания одних элементов ПО с другими. Эффективность (Efficiency) Эффективность - это способность ПО как можно меньше зависеть от ресурсов оборудования.

Внешние факторы Переносимость (Portability) Переносимость - это легкость переноса ПО в различные программные и аппаратные среды. Простота использования (Easy of Use) Простота использования - это легкость, с которой люди с различными знаниями и квалификацией могут научиться использовать ПО и применять его для решения задач.

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

Другие факторы Верифицируемость (Verifiability) - это легкость подготовки процедур приемки, особенно тестовых данных, процедур обнаружения неполадок и трассировки ошибок на этапах заключительной проверки и введения проекта в действие. Целостность (Integrity) - это способность ПО защищать свои различные компоненты (программы, данные) от несанкционированного доступа и модификации. Восстанавливаемость (Repairability) - это способность облегчать устранение дефектов. Экономичность (Economy) сочетается c своевременностью - это способность системы завершиться, не превысив выделенного бюджета или даже не истратив его.

Два пути работы над проектом: кривые Осмонда

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

Противоречия в требованиях Корректность и устойчивость Расширяемость и повторное использование

Преимущества использования OO- метода Совместимость Переносимость Простота использования Эффективность: Своевременность, экономичность и функциональность

Сопровождение ПО 70% стоимости ПО приходится на его сопровождение. Никакое изучение качества ПО не может быть удовлетворительным, если оно игнорирует этот аспект.

Понятие UML Язык объектно-ориентированного моделирования UML (Unified Modeling Language) разработан и развивается консорциумом OMG (Object Management Group) и имеет много общего с объектными моделями, на которых основана технология распределенных объектных систем CORBA, и объектной моделью ODMG (Object Data Management Group). UML позволяет моделировать разные виды систем: программные, аппаратные, программно-аппаратные, смешанные, явно включающие деятельность людей и т. д. UML активно применяется для проектирования реляционных БД. Для этого используется небольшая часть языка (диаграммы классов)

Классы, атрибуты и операции Диаграммой классов в терминологии UML называется диаграмма, на которой показан набор классов, а также связей между этими классами. Кроме того, диаграмма классов может включать комментарии и ограничения. Ограничения могут неформально задаваться на естественном языке или же могут формулироваться на языке объектных ограничений OCL (Object Constraints Language).

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

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

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

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

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

Классы, атрибуты и операции Класс Человек с определенными операциями: Для класса Человек мы определили три операции: выдатьВозраст, сохранитьТекущийДоход, выдатьОбщийДоход. Состояние объекта меняется при выполнении только второй операции. Результаты первой и третьей операций формируются на основе текущего состояния объекта.

Категории связей. Связь-зависимость В диаграмме классов могут участвовать связи трех разных категорий: зависимость (dependency), обобщение (generalization) и ассоциация (association). При проектировании реляционных БД наиболее важны вторая и третья категории связей, поэтому связи- зависимости будем рассматривать в общем виде.

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

Категории связей. Связь-зависимость Пример диаграммы классов со связью-зависимостью: Зависимость показывается прерывистой линией со стрелкой, направленной к классу, от которого имеется зависимость. Связи-зависимости существенны для объектно- ориентированных систем (в том числе и для ООБД). При проектировании реляционных БД непонятно, что делать с зависимостями (как воспользоваться этой информацией в реляционной БД?).

Связи-обобщения и механизм наследования классов в UML Связью-обобщением называется связь между общей сущностью, называемой суперклассом, или родителем, и более специализированной разновидностью этой сущности, называемой подклассом, или потомком. Обобщения иногда называют связями «is a», имея в виду, что класс-потомок является частным случаем класса-предка. Класс-потомок наследует все атрибуты и операции класса-предка, но в нем могут быть определены дополнительные атрибуты и операции.

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

Связи-обобщения и механизм наследования классов в UML Пример иерархии одиночного наследования классов:

Связи-обобщения и механизм наследования классов в UML Одиночное наследование является достаточным в большинстве случаев применения связи-обобщения. Однако в UML допускается и множественное наследование, когда один подкласс определяется на основе нескольких суперклассов:

Связи-обобщения и механизм наследования классов в UML Множественное наследование порождает ряд проблем, из которых одной из наиболее известных является проблема именования атрибутов и операций в подклассе, полученном путем множественного наследования. Пример: при образовании подклассов Студент и Преподаватель в них обоих был определен атрибут с именем номерКомнаты. Для объектов класса Студент значениями этого атрибута будут номера комнат в студенческом общежитии, а для объектов класса Преподаватель – номера служебных кабинетов. Как быть с объектами класса СтудентПреподаватель, для которых существенны оба одноименных атрибута (у студента-преподавателя могут иметься и комната в общежитии, и служебный кабинет)?

Связи-обобщения и механизм наследования классов в UML На практике применяется одно из следующих решений: запретить образование подкласса СтудентПреподаватель, пока в одном из суперклассов не будет произведено переименование атрибута номерКомнаты; наследовать это свойство только от одного из суперклассов, так что, например, значением атрибута номерКомнаты у объектов класса СтудентПреподаватель всегда будут номера служебных кабинетов; унаследовать в подклассе оба свойства, но автоматически переименовать оба атрибута, чтобы прояснить их смысл; назвать их, например, номерКомнатыСтудента и номерКомнатыПреподавателя.

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

Связи-обобщения и механизм наследования классов в UML Сложность проблемы именования атрибутов и операций несопоставимо меньше сложности реализации множественного наследования в реляционных БД. При использовании UML для проектирования реляционных БД нужно очень осторожно использовать наследование классов вообще и стараться избегать множественного наследования.

Связи-ассоциации: роли, кратность, агрегация Ассоциацией называется структурная связь, показывающая, что объекты одного класса некоторым образом связаны с объектами другого или того же самого класса. Допускается, чтобы оба конца ассоциации относились к одному классу. В ассоциации могут связываться два класса, и тогда она называется бинарной. Допускается создание ассоциаций, связывающих сразу n классов (они называются n-арными ассоциациями). Графически ассоциация изображается в виде линии, соединяющей класс сам с собой или с другими классами.

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

Связи-ассоциации: роли, кратность, агрегация Пример именованной ассоциации: Треугольник показывает, что именованная ассоциация должна читаться как «Студент учится в Университете».

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

Связи-ассоциации: роли, кратность, агрегация В примере показаны две ассоциации между классами Человек и Университет, в которых эти классы играют разные роли. Объекты класса Человек могут выступать в роли РАБОТНИКОВ при участии в ассоциации, в которой объекты класса Университет играют роль НАНИМАТЕЛЯ. В другой ассоциации объекты класса Человек играют роль СТУДЕНТА, а объекты класса УНИВЕРСИТЕТ – роль ОБУЧАЮЩЕГО.

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

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

Связи-ассоциации: роли, кратность, агрегация Например, указание «1» говорит о том, что каждый объект класса с данной ролью должен участвовать в некотором экземпляре данной ассоциации, причем в каждом экземпляре ассоциации может участвовать ровно один объект класса с данной ролью. Указание диапазона «0..1» говорит о том, что не все объекты класса с данной ролью обязаны участвовать в каком-либо экземпляре данной ассоциации, но в каждом экземпляре ассоциации может участвовать только один объект.

Связи-ассоциации: роли, кратность, агрегация Указание диапазона «1..*» говорит о том, что все объекты класса с данной ролью должны участвовать в некотором экземпляре данной ассоциации, и в каждом экземпляре ассоциации должен участвовать хотя бы один объект (верхняя граница не задана). Толкование диапазона «0..*» является очевидным расширением случая «0..1».

Связи-ассоциации: роли, кратность, агрегация В более сложных (но крайне редко встречающихся на практике) случаях определения кратности можно использовать списки диапазонов. Например, список «2, 4..6, 8..*» говорит о том, что все объекты класса с указанной ролью должны участвовать в некотором экземпляре данной ассоциации, и в каждом экземпляре ассоциации должны участвовать два, от четырех до шести или более семи объектов класса с данной ролью.

Связи-ассоциации: роли, кратность, агрегация На диаграмме классов показано, что произвольное (может быть, нулевое) число людей являются сотрудниками произвольного числа университетов: Каждый университет обучает произвольное (может быть, нулевое) число студентов, но каждый студент может быть студентом только одного университета.

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

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

Связи-ассоциации: роли, кратность, агрегация Бывают случаи, когда связь «части» и «целого» настолько сильна, что уничтожение «целого» приводит к уничтожению всех его «частей». Агрегатные ассоциации, обладающие таким свойством, называются композитными, или просто композициями. При наличии композиции объект-часть может быть частью только одного объекта-целого (композита). При обычной агрегатной ассоциации «часть» может одновременно принадлежать нескольким «целым». Графически композиция изображается в виде простой ассоциации, дополненной закрашенным ромбом со стороны «целого».

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

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

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

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