
- •Оглавление
- •Об авторе
- •Посвящение
- •Благодарности
- •Ждем ваших отзывов!
- •Что такое .NET
- •Создание исходной программы
- •Тестовая поездка
- •Каркас программы
- •Комментарии
- •Введение в хитрости панели элементов
- •Повторное использование кода из панели элементов
- •Правила объявления переменных
- •Вариации на тему int
- •Объявление переменной с плавающей точкой
- •Ограничения переменных с плавающей точкой
- •Объявление переменных типа decimal
- •Сравнение десятичных и целых чисел, а также чисел с плавающей точкой
- •Логичен ли логический тип
- •Символьные типы
- •Что такое тип-значение
- •Неизменяемость строк
- •Основные операции над строками
- •Сравнение строк
- •Сравнение без учета регистра
- •Отличие строк в разных регистрах
- •Преобразование символов строки в символы верхнего или нижнего регистра
- •Поиск в строках
- •Как искать
- •Пуста ли строка
- •Удаление пробельных символов
- •Анализ числового ввода
- •Обработка последовательности чисел
- •Объединение массива строк в одну строку
- •Арифметика
- •Простейшие операторы
- •Порядок выполнения операторов
- •Оператор инкремента
- •Сравнение чисел с плавающей точкой
- •Составные логические операторы
- •Вычисление типа операции
- •Типы при присваивании
- •Перегрузка операторов
- •Ветвление с использованием if и switch
- •Инструкция if
- •Инструкция else
- •Как избежать else
- •Вложенные инструкции if
- •Конструкция switch
- •Циклы
- •Цикл без счетчика
- •Правила области видимости
- •Пример
- •Зачем нужны разные циклы
- •Зачем нужны массивы
- •Массив фиксированного размера
- •Массив переменного размера
- •Свойство Length
- •Инициализация массивов
- •Понятие <т>
- •Обобщенные коллекции
- •Инстанцирование пустого списка
- •Создание списка целых чисел
- •Преобразования списков в массивы и обратно
- •Подсчет количества элементов в списке
- •Поиск в списках
- •Инициализаторы массивов и коллекций
- •Выполнение специфичных для множеств задач
- •Создание множества
- •Добавление элемента в множество
- •Выполнение объединения
- •Пересечение множеств
- •Получение разности
- •Не используйте старые коллекции
- •Обход каталога файлов
- •Начало программы
- •Получение начальных входных данных
- •Создание списка файлов
- •Форматирование вывода
- •Вывод в шестнадцатеричном формате
- •Обход коллекций: итераторы
- •Доступ к коллекции: общая задача
- •Использование foreach
- •Формат индексатора
- •Блок итератора
- •Создание каркаса блока итератора
- •Итерирование дней в месяцах
- •Что же такое коллекция
- •Синтаксис итератора
- •Блоки итераторов произвольного вида и размера
- •Обобщенные классы безопасны
- •Обобщенные классы эффективны
- •Очередь с приоритетами
- •Распаковка пакета
- •Написание обобщенного кода
- •Использование простого необобщенного класса фабрики
- •Незавершенные дела
- •Ковариантность
- •Использование механизма исключений для сообщения об ошибках
- •Что происходит при генерации исключения
- •Исключительный пример
- •Что делает этот пример "исключительным"
- •Трассировка стека
- •Советы по написанию кода с хорошей обработкой ошибок
- •Анализ возможных исключений метода
- •Как выяснить, какие исключения генерируются теми или иными методами
- •Генерирующие исключения выражения
- •Работа с перечислениями
- •Создание перечислений с инициализаторами
- •Указание типа данных перечисления
- •Применение перечислений в конструкции switch
- •Процедурные поездки
- •Объектно-ориентированные поездки
- •Определение класса и объекта
- •Определение класса
- •Что такое объект
- •Различие между объектами
- •Работа со ссылками
- •Классы, содержащие классы
- •Определение константных членов-данных и членов-данных только для чтения
- •Передача аргументов методу
- •Передача методу нескольких аргументов
- •Соответствие определений аргументов их использованию
- •Перегрузка методов
- •Реализация аргументов по умолчанию
- •Возврат значения оператором return
- •Кортеж с двумя элементами
- •Создание кортежей более чем с двумя элементами
- •Глава 14 Поговорим об этом
- •Определение методов
- •Определение статического метода
- •Определение метода экземпляра
- •Полное имя метода
- •Ключевое слово this
- •Когда this используется явно
- •Что делать при отсутствии this
- •Использование локальных функций
- •Прочие уровни безопасности
- •Методы доступа
- •Пример управления доступом
- •Выводы
- •Статические свойства
- •Побочные действия свойств
- •Дайте компилятору написать свойства для вас
- •Методы и уровни доступа
- •Замена конструктора по умолчанию
- •Конструирование объектов
- •Непосредственная инициализация объекта
- •Конструирование с инициализаторами
- •Инициализация объекта без конструктора
- •Определение свойств с кодом
- •Определение конструкторов и деструкторов с кодом
- •Определение методов доступа к свойствам с кодом
- •Определение методов доступа к событиям с кодом
- •Наследование класса
- •Более сложный пример наследования
- •ЯВЛЯЕТСЯ или СОДЕРЖИТ
- •Доступ к BankAccount через содержание
- •Отношение СОДЕРЖИТ
- •Заменяемость классов
- •Неверное преобразование времени выполнения
- •Указание конкретного конструктора базового класса
- •Обновленный класс BankAccount
- •Перегрузка унаследованного метода
- •Простейший случай перегрузки метода
- •Различные классы, различные методы
- •Сокрытие метода базового класса
- •Вызов методов базового класса
- •Что неверно в стратегии использования объявленного типа
- •Использование is для полиморфного доступа к скрытому методу
- •Объявление метода виртуальным и перекрытие
- •Получение максимальной выгоды от полиморфизма
- •Разложение классов
- •Абстрактный класс: ничего, кроме идеи
- •Как использовать абстрактные классы
- •Создание абстрактных объектов невозможно
- •Опечатывание класса
- •Реализация интерфейса
- •Именование интерфейсов
- •Наследование и реализация интерфейса
- •Преимущества интерфейсов
- •Тип, возвращаемый методом
- •Что скрыто за интерфейсом
- •Гибкие зависимости через интерфейсы
- •Реализация отношения СОДЕРЖИТ с помощью интерфейсов
- •Определение делегата
- •Пример передачи кода
- •Делегирование задания
- •Очень простой первый пример
- •Более реальный пример
- •Создание приложения
- •Жизненный цикл делегата
- •Анонимные методы
- •Проектный шаблон Observer
- •Что такое событие. Публикация и подписка
- •Как издатель оповещает о своих событиях
- •Как подписаться на событие
- •Как опубликовать событие
- •Как наблюдатели "обрабатывают" событие
- •Сборки
- •Выполнимые файлы
- •Библиотеки классов
- •Создание проекта библиотеки классов
- •Создание автономной библиотеки классов
- •Создание классов для библиотеки
- •Использование тестового приложения
- •Дополнительные ключевые слова для управления доступом
- •protected: поделимся с подклассами
- •protected internal: более изощренная защита
- •Размещение классов в пространствах имен
- •Объявление пространств имен
- •Пространства имен и доступ
- •Использование полностью квалифицированных имен
- •Ссылочные типы
- •Выходные параметры
- •Альтернативные методы возврата значений
- •Работа с переменными out
- •Возврат значений по ссылке
- •Различия типов-значений
- •Когда следует использовать структуры
- •Добавление распространенных элементов структур
- •Управление отдельной записью
- •Добавление структур в массивы
- •Перекрытие методов
- •Определение того, что следует защищать
- •Документирование компонентов программы
- •Разложение компонентов на функции
- •Оценка рисков
- •Аутентификация с использованием входа в Windows
- •Безопасность развертывания
- •Уязвимости сценариев
- •Наилучшие методы защиты приложений Web Forms
- •Получение данных
- •Настройка образца схемы базы данных
- •Подключение к источнику данных
- •Работа с визуальными инструментами
- •Написание кода для работы с данными
- •Использование Entity Framework
- •Где водится рыба: файловые потоки
- •Потоки
- •Читатели и писатели
- •Пример использования потока
- •Как это работает
- •Наконец-то мы пишем!
- •Использование конструкции using
- •Загрузка файла из Интернета
- •Регистрация сетевой активности
- •Графика
- •Перья
- •Кисти
- •Текст
- •Классы рисования и каркас .NET
- •Приступая к работе
- •Настройка проекта
- •Обработка счета
- •Создание подключения к событию
- •Рисование доски
- •Запуск новой игры

ВВОВ |
КDa |
-s· r . ПОЗВo |
eВНД ЕТС1ОДОЗeСААВors! re! |
! |
:!К |
ОСО |
o;-К :s |
ДВОДСВЗНОСОДТОВОeСААВОНПОЗВeВНОСО or--D |
rr |
ВВОВ |
|||
rs re |
;К-as·sD i ОАВСВВАНЕТВ1И1ЗВНВНИИЕСДЕДОВПСИВtОДЕ1ОДВ |
|||||
СС1eИeВНИ1 |
1СВОtОЕСeВОСС1СВiВНИВ ДЕ1ОДС l К; a -s· |
i oОАBoВАВЗ |
||||
ДeНВВАНСОАНОДСНИИВТС ДОДСВЗНДЕТОeНВНИНТСОtССЗЗЕl |
||||||
ОBВЕВВБООНОЗНЕТСИОЕТ2НДeВНИИЗВВОВОДИСВBeСЕНЕЗИr /АВ ИЗВВВ |
||||||
АДО3 cВНB\ВСОeВОИАТОeЕ1BИВВОe3eВДОВАeОДОo;-К :s |
ВОeЕООПСИ |
|||||
НВОЕТrОВИЗОАВИcВОa ООЗПСОЗИААЗВ!ВB ОeСААОЗООВОСS ЕИ ОeВНЕtИЕТ |
СОВЕТ |
ЕТООИ ЗО!ВВ ЕТЕВЕТВСВОСЕВ АОЗНО!ВАВДОЗДИСВBСeЕНЕrЗВВОВОД04 |
|
|
|
И ОeСААОЗООВОСЕИ\ НВВОАВСВОeНОtИЕТОО ИНВАОВВС!ИВНИeВtОДИСЕТ |
|
ВBСeЕНОtО04a |
Получение максимальной выгоды от полиморфизма
!e3 S!:(-!,f(2-( |
O! -)!F!- |
!-)!O()( |
)( |
h!-т>h! .!:(-!,f)0# |
!2З |
||||||||
#.h0 |
(-.!:3217 |
h !.() |
( h!h 6# ()h#, f#3-ч |
(S,(-#, |
O (#,(,F(( |
!2З#.h!O |
|||||||
птeы |
|
rnп |
г Нern |
rnПeoТ(hr.,г |
|
-!6)! |
|
->(h(h3т >h! O-# O(.0 |
f(F1, |
||||
(-#7h -O!3 -#h!. |
rne d |
#h!. |
rne |
.(6.!F! |
|
(2 !2 |
#.h!O -(-! |
-!2!3 |
,#( |
||||
:(2!O() |
S! |
-O!#-ч1 |
! F: (O)!# Oh!-и>h! .:1 |
.!::#. |
c(( h(.(F !2З#.h!O |
-!6)! |
|||||||
(-S!:32!O(h3 |
c(.: |
|
rn |
.!hep!,03т |
21.#h |
O020O(h3-#h!. rne |
(:( :72!3 |
||||||
.,1F!3 |
-#h!. S!:(-!,f)!F! |
|
()h#,f#3-( |
!2З#.h |
!Oun |
|
|
|
Визитная карточка класса:
метод ToString ( )
n)" ,.#) |
), |
'1#).",-.T |
|
!.O$. |
.#.!1,<,. |
,.#)) |
) |
$(,1"'1"(,1 |
|
d_ _T!$T |
-,!(,1- |
|
'1-T. |
.T! |
TT!T |
,.#)) |
1,<,...#"T |
(,1"T!, |
_i в aД |
,!T!'1,. |
,'1"!.'1#.-"T |
)!,"'1_ |
|||
.$(,1!" |
!.t",T# |
1,< )T'1!,- |
f!_ iАaДJJ ,"- |
1,< T!(,1 |
.T! |
,#.,,. |
, |
#)) ,!.."'1 |
1t1"'1"_ |
|||
,'1, |
1,<#T. (,1"T!, |
|
вАiaД |
.T!., |
$(,1"T. |
1,<!.(,1!.'1!)T. |
1,<,1,<! |
,# |
)1,<!$0 !. |
", T!1,< |
. 0 ..._ #,_ Полиморфизм 391

Абстракционизм в С#
|
|
.(# |
ь |
)., |
|
,(.п,n |
|
|
#. ."О .#. |
)!'1!.". |
|
.,. |
.! |
,..'1.n |
|
..#- |
,(.D# |
,'1",)(#)_ |
|
|||
,-"( |
.#.!. |
|
|
(!,!,)., |
|
,(.п |
|
! !.'1#('1#- |
)(!'1!'1# |
(,1",#,. |
) |
(!(,1е |
.(! ... |
|
,(.D, |
|
||||||
.!(!'1#- |
|
.,,# |
., |
,(.D". |
)!!.с"З |
_ (!... |
|
.'1"'1.- |
,'1! |
'1#(,1(,1.'1!)#'1.- |
|
T(! |
!.'1#em |
|||||||||
.#" |
е.(! |
|
))" |
!.р".(, |
|
|
АuГ-l),-.()- |
T.."(,1,,-'1#(,1. |
.#. .0 |
(!,!,.,#))!) |
|
|
|
uНГl |
||||||||
'1! |
'1" )-с")()-"( |
|
'1. |
|
!,'1!6! |
T.."(,1,,-'1# |
.,#))# |
|
uНГln |
#. .(! ." |
(#.!" |
|
|
,(.D# |
||||||||
(! ))"6,# |
.#.!. |
(! |
.!'1.'1"('1,. |
)., |
р |
,.'1 |
|
).'1е |
.-'1.D# |
.,. |
. |
,'1. (,1"'1- |
)('1# |
-)_ |
||||||||
|
#.,.. |
|
'1," |
|
(.,, |
|
,(.D |
.(,1".( |
(,1'1!.")()! |
|
!.с.0 |
))!.)() |
В) |
,'1!(. |
)'1!(,1 |
),-_ |
||||||
.#" |
!'1. |
., |
'1" |
.,,. |
|
,(.D#(,1.oе |
'1! |
'1"( |
,)-0 |
(.,!) |
- .!(!'1,0 |
., |
!.с.(,1. |
|
|
.,,. |
|
|||||
))" |
))!.)()#З |
|
о),. |
., |
(#.." |
(., , |
.,,. |
|
!'1. |
.,,. |
., |
!,. |
'1#.!),(,1 |
. |
(.,#(,1 |
.е |
||||||
'1.."(,1 |
'1" !(,..#.с.(,1.)- |
|
|
,'1- |
!( |
,'1- |
#n |
|
|
|
|
|
|
|
|
|
|
Разложение классов
|
7.7 |
-7- ,#-(,727 ,17, |
!2 #<,0т-0.#.11 |
7F !2 |
7# >#,,0Ш ,!20 |
1-7.#,3 |
|||||||||||
<(< g,! ,(2!,( # |
,(т---!, |
,7- .-( <.(--( |
|
|
ПТhrтп |
7 |
imaimaoП SrМдimг |
.!<( |
|||||||||
2())0# |
)( |
|
,7-i |
Шd .#-3 ..1 |
|
!.7-()71 |
<. (--!- |
7-.!.32!-() |
)7f7c7,!-()i |
||||||||
)03 120< -!.#.7,!-()71 |
|
С |
х |
Ч Т |
Ч |
х гх |
г |
Ч |
unW,(f7>#-<73 |
||||||||
120< |
!.7-0-(7 73 |
..(- |
-0 |
7 7F -2(7-!! |
,)!ch#) |
71 .,1W - .,1W!-t |
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
University |
|
|
|
|||
|
|
|
HighSchool |
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
- numStudents |
|
|
|
|||||
|
|
|
- numStudents |
|
* Student |
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
+ avgSAT |
|
|
|
|
|
|
|
|
+ Enroll ( ) |
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
+ Eпroll ( ) |
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
+ GetGrant ( ) |
|
|
|
||
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
Рис. 1 7. 1. ИМL-описание классов HighSchool и Иniversi04б |
|
392 ЧАСТЬ 2 Объектно-ориентированное программирование на С#

Как видно на рис. 1 7. 1 , у школы и университета много общих свойств. И у школы, и у университета имеется открытый метод Enroll ( ) для добавления объекта Student (зачисления в учебное заведение). Оба класса имеют закры тый член nurnStudents, в котором хранится ч исло учащихся. Еще одно общее свойство - взаимоотношения учащихся и учебных заведений: в учебном за ведении может быть много учащихся, в то время как один учащийся учится одновременно только в одном учебном заведении. Само собой, имеется масса других свойств учебных заведений, но для данного рассмотрения ограничимся перечисленным.
Вдополнение к свойствам школы университет содержит метод GetGrant ( )
ичлен-данные avgSAT.
Унифицированный язык моделирования (Unified Modeling Language - UML) представляет собой выразительный язык, спо- собный ясно определять взаимоотношения объектов в программе.
Одно из достоинств UML заключается в том, что вы можете не зависеть от кон кретного языка программирования.
Ниже перечислены основные свойства UML.
•Классы представлены прямоугольниками, разделенными по вертикали на три части. Имя класса указывается в верхней части прямоугольника.
•Члены-данные класса находятся в средней части, а методы - в нижней. Можно опустить среднюю или нижнюю часть прямоугольника, если в клас се нет членов-данных или методов.
•Члены со знаком плюс (+) перед именем являются открытыми, со знаком ми нус (-) - закрытыми. В UML отсутствует специальный знакдля защищенных членов, но некоторые программисты используют для обозначения таких членов символ #. Закрытые члены доступны только для других членов того же класса; открытые члены доступны всем классам.
•Метка { abstract } после имени указывает абстрактный класс или метод. На самом деле UML использует для этого иное обозначение, но так мне ка жется проще. Можно также использовать для абстрактных методов курсив.
•Стрелка между двумя классами представляет отношение между ними. Число над линией означает мощность - сколько элементов может быть
скаждого конца стрелки. Звездочка (*) означает rsОаiiО3вэОаи На"3ОциЕсли число опущено, по умолчанию предполагается значение 1 . Таким образом, на рис. 1 7.1 видно, что один университет может иметь сколько угодно сту дентов - они связаны отношением "один-ко-многим':
ГЛАВА 1 7 Полиморфизм 393

•Линия с большой открытой или треугольной стрелкой на конце выражает отношение ЯВЛЯЕТСЯ (наследование). Стрелка указывает в иерархии клас сов на базовый класс. Другие типы взаимоотношений включают отношение СОДЕРЖИТ, которое указывается линией с закрашенным ромбиком со сто роны владельца.
лвуса |
на риоe с НТ сдриусрусаг наоеерзее гте веьсеинеt не еsрзeая |
ааотз |
|
инкерса.ии |
итерлртутоР) а итериреванлу |
в ееиу тл ииаарассав i .) |
еотавп |
ряут нудриятнтж итeее/ Нт сеиуту тсунзe |
итз итериреваниу. деьверяя наору |
иеватз ееруу ореинтж ераоо aанaдемдетaLaет ееруу дреоте,е ераооа lнe юраюиив.a еае дееаьане на риод Н ye
тлрыбоаччлс в )дпыийий)адс нсп)ч ч р р со а с
е)ванч Аокос
рсьаеыeес тсднщд.нвкс о и с
Рис. 1 7.2. Наследование HighSchool упрощает класс Ипiversiл.. но приводит к проблемам
ожиььодясжчсааВ.оьвиувьаруаонуррпнз ро ажиьь2ил.щотыав".. ыса квон ысоД
.у оыаьиво8гойро ьаиЫивонвоs 2ир.щотылвг E кво ажиььврясжчсааи.ь нжурон ищяжбB.а нувоАон "йф"sфeф.n у дАриаa . о виаоу сунурау ануув оАрлмлрАинурQ
вижорлт ысозжунл лрамусьан в |
квомомьуру наожиьо ьыураижорпна ьмоае |
ьвмине8 |
жимроуенво риьжуАомираусизовиув е каоV |
-п нойуну ьаиuиноcол а нвон |
ронав рине льажеа•uCи аорунрозкво виаыро ьаиоирроумпну ; ру ысоьво ьважаьвануьаиа всамаижороьво8иаоу румусроуысуАьвимжураунойув ммуьва моизжлйАурауысо»синнаьви аиа ьуаниьsвиа а мзлАл.уня i оАар ысуасиьрпа Ауроунлs руориаононл ь минене моальинаа ысаАувьа навивое сиозасивоьа м минас аьсоАрпс вуаьвисиа виаоу румусроуысуАьвимжуреунойув ысамуьва а руысимажоронлыоранират ысо»синнпо
осону вотоирумусроуысуАьвимжуреу нойув ысамуьва а суижордн ысозжуN нино .суАыожойанН нво мнаожусунежа мпзасиво жлннутолнурааиrе Ажяквое »оысотсиннаьв ысоьво Аозимжяувмажиььо.я сжчсааи.нувоА диногищатн.во.з.у2. . лаиuпмит.аа ана виаотолнурааио
394 ЧАСТЬ 2 Объектно-ориентирован ное программирование на С#

И вот - проблема. В университете не намерены определять лучшего сту дента, но метод NameFavorite ( ) оказывается унаследованным. Это может показаться небольшой проблемой - в конце концов, этот метод в классе University можно просто игнорировать. Да, один лишний метод не делает погоды, но это еще один кирпич в стене непонимания. Постепенно лишние члены-данные и методы накапливаются, и наступает момент, когда ваш класс уже не в состоянии вынести такой багаж. Несчастный программист уже не по нимает, какие методы "реальны", а какие - нет.
приводит и к другим проблемам. При наследовании, показанном на рис. 17.2, как видно из схемы, классы
Universitу и HighSchool имеют одну и ту же процедуру зачисления. ЗАПОМНИ! Как бы странно это ни звучало, будем считать, что это так и есть.
Программа разработана, упакована и отправлена потребителям. Не сколькими месяцами позже министерство просвещения решает из менить правила зачисления в школы, что, в свою очередь, приводит к изменению процедуры зачисления и в университеты, что, конечно же, неверно.
Чтобы избежать указанной проблемы, следует осознать, что университет не является разновидностью школы. Отношение СОДЕРЖИТ также не будет работать - ведь университет не содержит школу, как и школа не содержит университет. Решение заключается в том, что и школа, и университет - это специальные типы учебных заведений.
На рис. 17.3 показано более корректное отношение. Новый класс School содержит общие свойства двух типов учебных заведений, включая отношения с объектами Student . Более того, класс School даже имеет метод Enroll ( ) , хотя он и абстрактный, поскольку и University, и HighSchool реализуют его по-разному.
Теперь классы Univers i t y и HighSchool наследуют общий базовый класс. Каждый из них содержит свои уникальные члены: HighSchool - Name Favorite ( ) , а University - GetGrant ( ) . Кроме того, оба класса перекрывают метод Enroll ( ) , описывающий правила зачисления учащихся в разные учеб ные заведения. По сути, здесь выделено общее путем создания базового клас са из двух схожих классов, которые после этого стали подклассами. Введение класса School имеет как минимум два больших преимущества.
)) Это соответствует реаnьности. Университет является учебным за ведением, но не школой. Соответствие действительности - важное, но не главное преимущество.
я тутжосж |
Полиморфизм |
xГАн |
к |
|

Рис. 17.З. Классы University и HighSchool
должны иметь общий базовый класс School
)) Это изолирует один класс от изменений или дополнений в другой класс. Если потребуется, например, внести дополнения в класс Universitу, то его новые методы никак не повлияют на класс
HighSchool.
Процесс выделения общих свойств из схожих классов называется 4)v :ли тиE 2и" классов (factoring). Это важное свойство объектно-ориентированных языков программирования как по описанным выше причинам, так и с точки зрения снижения избыточности.
Разложение корректно только в том случае, если отношения насле дования соответствуют действительности. Можно выделять общие свойства классов Mouse и Joystick, поскольку оба они представляют ВНИМАНИ8 собой указывающие устройства, но делать то же для классов Mouse и
Display будет ошибкой.
Разложение обычно приводит к нескольким уровням абстракции. Напри мер, программа, охватывающая более широкий круг школ, может иметь струк туру классов, показанную на рис. 1 7.4.
Как видите, внесено два новых класса между Uni ve r s i t y и S chool: HigherLearning и LowerLevel. Например, новый класс HigherLearning делит ся на классы College и Universitу. Такая многослойная иерархия - обычное и даже желательное явление при разложении, соответствующем реальному миру.
396 ЧАСТЬ 2 Объектно-ориентированное программирование на С#