Здравствуйте! Записался на ваш курс, но не понимаю как произвести оплату. Надо ли писать заявление и, если да, то куда отправлять? как я получу диплом о профессиональной переподготовке? |
Отношения между классами. Клиенты и наследники
Проект к данной лекции Вы можете скачать здесь.
Отношения между классами
Класс, как не раз отмечалось, играет две роли: он является модулем - архитектурной единицей, и он имеет содержательный смысл, определяя некоторый тип данных. Продолжая аналогию с ролями, заметим, что программная система, представляющая собой множество классов, является ансамблем, в котором каждый класс играет свою роль не независимо, а во взаимодействии с другими актерами этого ансамбля.
Классы программной системы находятся в определенных отношениях друг с другом. Два основных типа отношений между классами определены в ОО-системах. Первое отношение, "клиенты и поставщики", называется часто клиентским отношением или отношением вложенности (встраивания). Второе отношение, "родители и наследники", называется отношением наследования.
Определение 1. Классы A и В находятся в отношении "клиент - поставщик", если одним из полей класса В является объект класса А. Класс А называется поставщиком класса В, класс В называется клиентом класса А.
Следуя этому определению, объект класса A "вложен" в класс B. По этой причине отношение "клиент - поставщик" называют также отношением вложенности или встраивания. Заметим сразу, что помимо вложенности поля, могут существовать и другие способы взаимодействия двух классов, связывающие их отношением "клиент - поставщик".
Определение 2. Классы А и В находятся в отношении "родитель - наследник", если при объявлении класса В класс А указан в качестве родительского класса. Класс А называется клиентом класса В, класс В называется наследником класса А.
Графически отношения между классами изображаются с использованием стрелок, соединяющих классы. Стрелка идет от класса клиента к классу поставщика, от наследника к родительскому классу. Вложенность отображается стрелкой с двойной линией, наследование - толстой одиночной линией. На рис. 4.1 показано графическое изображение классов, связанных отношениями наследования и вложенности.
Оба отношения, наследования и вложенности, являются транзитивными. Если В - клиент А и С - клиент В, то отсюда следует, что С - клиент А. Если В - наследник А и С - наследник В, то отсюда следует, что С - наследник А.
Определения 1 и 2 задают прямых или непосредственных клиентов и поставщиков, прямых родителей и наследников. Вследствие транзитивности необходимо ввести понятие уровня. Прямые клиенты и поставщики, прямые родители и наследники относятся к соответствующему уровню 1 (клиенты уровня 1, поставщики уровня 1 и так далее). Затем следует рекурсивное определение: прямой клиент клиента уровня k относится к уровню k+1.
Для отношения наследования используется терминология, заимствованная из естественного языка. Прямые классы-наследники часто называются сыновними или дочерними классами. Непрямые родители называются предками, а их непрямые наследники - потомками.
Замечу, что цепочки вложенности и наследования могут быть достаточно длинными. На практике вполне могут встречаться цепочки длины 10. Например, библиотечные классы, составляющие систему Microsoft Office, полностью построены на отношении вложенности. При программной работе с объектами Word можно начать с объекта, задающего приложение Word, и добраться до объекта, задающего отдельный символ в некотором слове некоторого предложения одного из открытых документов Word. Для выбора нужного объекта можно задать такую цепочку: приложение Word - коллекция документов - документ - область документа - коллекция абзацев - абзац - коллекция предложений - предложение - коллекция слов - слово - коллекция символов - символ. В этой цепочке каждому понятию соответствует класс библиотеки Microsoft Office, где каждая пара соседствующих классов связана отношением вложенности.
Классы библиотеки FCL связаны как отношением вложенности, так и отношением наследования. Длинные цепочки наследования достаточно характерны для классов этой библиотеки.
Отношения "является" и "имеет"
При проектировании классов часто возникает вопрос, какое же отношение между классами нужно построить. Рассмотрим совсем простой пример двух классов - Square и Rectangle, описывающих квадраты и прямоугольники. Наверное, понятно, что эти классы следует связать скорее отношением наследования, чем вложенности; менее понятным остается вопрос, а какой из этих двух классов следует сделать родительским. Еще один пример двух классов - Car и Person, описывающих автомобиль и персону. Какими отношениями с этими классами должен быть связан класс Person_of_Car, описывающий владельца машины? Может ли он быть наследником обоих классов? Найти правильные ответы на эти вопросы проектирования классов помогает понимание того, что отношение "клиент - поставщик" задает отношение "имеет" ("has"), а отношение наследования задает отношение "является" ("is a"). В случае классов Square и Rectangle понятно, что каждый объект квадрат "является" прямоугольником, поэтому между этими классами существует отношение наследования и родительским классом является класс Rectangle, а класс Square является его потомком.
В случае автомобилей, персон и владельцев авто также понятно, что владелец "имеет" автомобиль и "является" персоной. Поэтому класс Person_of_Car является клиентом класса Car и наследником класса Person.
Диаграмма классов
В игрушечных системах с двумя-тремя классами, появляющихся в примерах этой книги и студенческих проектах, отношения между классами системы можно держать в голове. Когда в программной системе число классов приближается к десяти, а в реальных системах число классов может измеряться сотнями, то для проектирования системы и ее анализа графическое отображение отношений между классами становится крайне важным.
Рассмотрим начальный этап проектирования гипотетической программной системы, реализуемой в виде Windows-проекта. На этом этапе классы создаются, но без содержательной начинки. Но уже на этом этапе можно определить, какими отношениями классы связаны между собой.
В момент создания нового Windows-проекта автоматически строятся классы, отражающие специфику проектов такого типа. Так автоматически создается класс Program с точкой входа в проект - процедурой Main. Автоматически создается и класс Form1, являющийся прямым наследником класса Form из библиотеки FCL.
С первых шагов проектирования классам следует давать содержательные имена, в том числе выполняя переименование и классов, создаваемых автоматически. Переименуем в нашем примере класс Form1, дав ему имя MyForm.
В процедуре Main автоматически создается объект класса MyForm, так что класс Program становится клиентом класса MyForm. При проектировании интерфейса формы и размещения в ней элементов управления соответствующий инструментарий - дизайнер форм - добавляет программный код в класс MyForm. Для каждого элемента управления в класс добавляется поле, представляющее объект класса, определяющего этот элемент управления. Так, класс MyForm становится клиентом многих классов, характеризующих элементы управления, расположенные на форме. Для простоты примера на форме размещена только одна командная кнопка "Пуск", так что в нашем примере класс MyForm является клиентом класса Button из библиотеки FCL.
Добавим теперь в проект собственные классы. Создадим класс Testing и сделаем объект этого класса полем класса MyForm. Класс Testing станет поставщиком для класса MyForm, а последний будет клиентом класса Testing. Объект класса Testing будет создаваться в обработчике события Click командной кнопки "Пуск". Добавим в класс Testing три поля - три объекта классов Student, OwnerOfCar и Square, что делает класс Testing клиентом этих трех классов, которые также добавим в наш проект. Классы Student и OwnerOfCar сделаем прямыми наследниками класса Person, а класс OwnerOfCar - клиентом класса Car. Свяжем отношением наследования три класса, задающие геометрические фигуры - Square, Rectangle и Figure. Квадрат "является" прямоугольником, а прямоугольник "является" геометрической фигурой. Класс Figure имеет поле center класса Point, что делает его клиентом класса Point.
Хотя текстовое описание классов проекта я старался сделать информативным, но графическое представление более наглядно. В Visual Studio 2008 есть инструментарий, позволяющий строить диаграмму классов проекта. Для построения диаграммы в окне Solution Explorer достаточно выбрать имя проекта, нажать правую кнопку мыши и из выпадающего контекстного меню выбрать пункт View Class Diagram. Диаграмма классов проекта, названного Architecture, показана на рис. 4.2.
На диаграмме отображаются все классы проекта. Помимо описанных классов, на диаграмме показаны два класса, автоматически строящиеся для проектов - Resources и Settings, задающие ресурсы и установки проекта.
Каждый класс на диаграмме может быть раскрыт, отображая интерфейс класса. Диаграмма также показывает цепочки классов, связанных отношением наследования. Если класс имеет прямого родителя, то он указан в описании класса на диаграмме.
К сожалению, на диаграмме не отображаются отношения встраивания. Причина этому понятна. Достаточно просто понять из описания класса, кто является прямым родителем класса, поскольку он явно выписан в заголовке класса. Определить прямых поставщиков класса значительно сложнее. Определение 1 хотя и справедливо, но оно не описывает все ситуации, когда класс является поставщиком для другого класса. Как будет определено чуть ниже, помимо того, что поле класса является объектом другого класса (поставщика), возможны и другие ситуации, приводящие к возникновению отношения "клиент-поставщик". По этой причине полезно строить диаграмму классов и другими средствами, отображая на ней как отношения наследования, так и встраивания.
На рис. 4.3 показана такая диаграмма.
Среди классов, изображенных на рис. 4.3 , показан и класс object - прародитель всех классов. Фактически от всех классов системы ведет путь наследования к классу object, так что при рисовании полной картины наследования (отображая не только прямых родителей) из каждого класса выходит стрелка наследования, непосредственно или транзитивно ведущая к классу object. Класс object - это единственный класс, в который ведут несколько стрелок, но ни одна из стрелок не выходит. Этот класс не имеет ни родителей, ни клиентов. Особую роль играет и класс Program. Из него могут выходить несколько стрелок, но ни одна стрелка не входит. У этого класса нет потомков, нет клиентов. Никто не может создать объекты этого класса. Единственный объект этого класса создается автоматически в момент запуска программной системы на исполнение, и создается он вне программной системы высшими силами.
Дополняя друг друга, обе диаграммы, показанные на рис. 4.2 и рис. 4.3, дают достаточно полное представление об архитектуре проекта, облегчая процесс проектирования программной системы. Закончим на этом рассмотрение этапа проектирования программной системы и перейдем к более детальному рассмотрению отношений между классами.