|
|||||||||||||||||||
|
НаследованиеЦель науки состоит в том, чтобы описать вселенную. В достижении этой цели работа науки, в основном, заключается просто в создании генеалогических деревьев. Когда энтомологи вернулись с берегов Амазонки с неизвестным ранее насекомым в банке, их задача состояла в том, чтобы определить, куда следует поместить это насекомое в гигантской диаграмме, в которой собраны все научные названия всех насекомых. Такие же диаграммы существуют и для растений, рыб, млекопитающих, пресмыкающихся, химических элементов, внутриатомных частиц и других галактик. Все они выглядят как генеалогические деревья: единственная общая категория в вершине, с увеличивающимся числом расходящихся веером категорий ниже этой единственной категории. Внутри категории "насекомое", например, есть две ветви: насекомые с видимыми крыльями и насекомые со скрытыми крыльями или вообще без них. Ниже крылатых насекомых находится большое число категорий: мотыльки, бабочки, мухи и т.д. Каждая категория имеет подкатегории, а ниже этих подкатегорий находится еще больше подкатегорий (см. рис.4.1) Рисунок 1.1. Часть диаграммы категории насекомые. ┌───────────┐ │ насекомые │ └─┬───────┬─┘ ┌───────────────┘ │ │ │ ┌────┴─────┐ ┌───┴───────┐ │ крылатые │ │ бескрылые │ └┬───┬───┬─┘ └───────────┘ ┌────────┘ │ └───────┐ ┌───┴──────┐┌────┴────┐┌─────┴────┐ │ мотыльки ││ бабочки ││ мухи │ └──────────┘└─────────┘└──────────┘ Этот процесс классификации называется систематикой. Это хорошая метафора для механизма наследования объектно-ориентированного программирования. Вопросы, какие задают себе ученые при попытке классифицировать какое-то новое животное или объект: Насколько оно похоже на животное или объекты общего класса? Насколько оно отличается? Каждый различный класс имеет множество свойств и черт поведения, которые характеризуют его. Ученые начинают с верхушки семейного дерева образцов и спускаются по его ветвям, задавая себе эти два вопроса на протяжении всего пути. Наивысшие уровни всегда самые общие, и вопросы простейшие: с крыльями или без? Каждый уровень более специфичен по сравнению с предыдущим и является менее общим. Очевидно, ученые добрались до точки высчитывания волосинок на третьем суставе задних лапок насекомых - в самом деле, специфичное свойство (и основательная причина, возможно, по которой энтомологом лучше не быть). Важно запомнить, что как только свойство задано, все категории ниже этого определения содержат это свойство. Поэтому как только насекомое идентифицировано как член расположения diptera (муха), не нужно указывать заново, что муха имеет одну пару крыльев. Особи насекомых, которых мы называем мухами, наследуют это свойство из расположения в семейном дереве. Вскоре Вы узнаете, что объектно-ориентированное программирование очень напоминает процесс построения генеалогических деревьев для структур данных. Одной из важнейших вещей, добавляемых объектно-ориентированным программированием к традиционным языкам программирования таким, как Паскаль, является механизм наследования свойств для типов данных от более простых, более общих типов. Этим механизмом является наследование.
Объекты: записи, которые наследуют.В терминах Паскаля, объект очень напоминает запись, которая служит "оболочкой" для соединения нескольких связанных между собой элементов данных под одним именем. В графической среде мы должны взять вместе координаты X и Y позиции на графическом экране и назвать это типом записи с именем Location: Location = record X, Y : Integer; end; Location здесь является типом запись; это шаблон, который используется компилятором для создания переменных типа запись. Переменная типа Location - это экземпляр типа Location. Термин "экземпляр" используется сейчас в окружении Паскаля, но он всегда используется людьми, занимающимися ООП, и будет хорошо, если Вы начнете думать в терминах типов и экземпляров этих типов. О типе Location можно думать двумя способами: когда координаты X и Y нужны отдельно и когда Вы думаете о них, как о полях X и Y в записи. С другой стороны, если Вам нужно думать о координатах X и Y, действующих вместе для нахождения точки на экране, то Вы можете думать о них совокупно как о Location. Предположим, Вы хотите высветить точку в позиции, описанной на экране с помощью Location записи. В Паскале Вы можете добавить булевское поле, указывающее, светится ли пиксел в данной позиции, и сделать это новым типом записи: Point = record X, Y : Integer; visible : Вoolean; end; Если быть поумнее, то можно сохранить тип записи Location посредством создания поля типа Location внутри типа Point: Point = record Position : Location; Visible : Вoolean; end; Это работает, и программисты на Паскале занимаются этим все время. Одна вещь, которую этот метод не делает: он не заставляет Вас думать о сущности того, чем Вы манипулируете в своем программном обеспечении. Вам нужно задавать себе вопросы типа: "Чем точка на экране отличается от позиции на экране?" Ответ такой : Точка - это позиция на экране, которая светится. Подумайте еще раз о первой части этого утверждения: точка - это позиция ... В определении точки неявно присутствует позиция для этой точки (пикселы существуют только на экране). В объектно-ориентированном программировании мы признаем эту особую взаимосвязь. Поскольку все точки должны содержать позицию, мы говорим, что тип Point - это тип, порожденный типом Location. Point наследует все, что имеет Location, и добавляет нечто новое к Point, чтобы сделать Point тем, чем оно должно быть. Процесс, посредством которого один тип наследует свойства другого типа, называется наследованием. Наследник называется порожденным типом; тип, от которого наследует порожденный тип, называется родительским типом. Типы записей обычного Паскаля наследовать не могут. Turbo Pascal, однако, расширяет язык Паскаль для поддержки наследования. Одним из этих расширений является новая категория структуры данных, имеющая отношение к записям, но гораздо более мощная. Типы данных в этой новой категории задаются новым зарезервированным словом : object (объект). Тип объект может быть задан как законченный, автономный тип в стиле записей Паскаля, или может быть задан как порождение существующего типа объекта, посредством помещения имени родительского типа в круглых скобках после зарезервированного слова object. В графическом примере, который мы только что рассмотрели, два типа объекта можно задать соответственно таким способом: type Location = object X, Y : Integer; end; Point = object(Location) visible : Вoolean; end; Примечание: Отметим использование здесь круглых скобок для обозначения наследования. Здесь Location является родительским типом, а Point - порожденным типом. Как Вы увидите позднее, процесс может продолжаться бесконечно: можно задать наследников типа Point, наследников типа, порожденного от Point и т.д. Большая часть применений объектно-ориентированного проектирования состоит в построении этой иерархии объектов, выражающей семейное дерево объектов. Все возможные типы, порожденные от Location, называются Location порожденными типами, а Point - один из непосредственных наследников Location. Обратно, Location - непосредственный родитель для Point. Тип объект (как подсправочник DOS) может иметь любое число непосредственных наследников, но только одного непосредственного предка. Объекты тесно связаны с записями, как показывают эти определения. Новое зарезервированное слово object - наиболее очевидное отличие, но существует множество других отличий, некоторые из них очень тонкие, как Вы увидите позднее. Например: X и Y поля в Location не пишутся явно в типе Point, но Point их имеет, во всяком случае, благодаря наследованию. Можно говорить о значении Х типа Point, точно так же, как можно говорить о значении Х типа Location.
Экземпляры объектного типа.Экземпляры типа объект объявляются точно так же, как в Паскале объявляется любая переменная, либо как статические переменные, либо как указатель на переменные, размещенные в куче: type PointPtr = ^Point; var StatPoint : Point; {готово к использованию} DynaPoint : PointPtr; {перед использованием нужно разместить с помощью New}
Поля объекта.Доступ к полям данных объекта можно получить так же, как и в обычной записи; либо используя оператор With, либо используя точку. Например: MyPoint.Visible := false; With MyPoint do begin X := 341; Y := 42; end; Примечание: Не забывайте! Поля, наследуемые объектом, не обрабатываются особым образом просто потому, что они унаследованы. Сейчас, прежде всего, Вы должны запомнить (возможно, понимание этого придет естественно), что унаследованные поля доступны так же, как поля, объявленные внутри данного типа объекта. Например, хотя X и Y не являются частью объявления Point (они наследуются из типа Location), можно задавать их, как будто бы они объявлены внутри Point: MyPoint.X := 17;
Хорошая практика и плохая практика.Хотя к полям объекта можно получить прямой доступ, поступать так - не слишком хорошая идея. Принципы объектно-ориентированного программирования требуют, чтобы поля объекта оставались нетронутыми столько, насколько это возможно. Это ограничение вначале может показаться произвольным и грубым, но это - часть большой картины ООП, которую мы создаем в этой главе. Со временем Вы увидите смысл этой новой декларации для хорошей практики программирования, однако по ряду причин мы не можем раскрыть его сейчас полностью и пока примите на веру: избегайте прямого доступа к полям данных объекта. Примечание: Turbo Pascal сейчас позволяет Вам сделать поля и методы объекта личными (private). См. ниже "Раздел private". Итак - как получить доступ к полям объекта? Что устанавливает их и читает их? Примечание: Поля данных объекта - это то, что объект знает; его методы - это то, что объект делает. Ответ такой: для доступа к полям данных объекта нужно использовать методы объекта, где только возможно. Метод - это процедура или функция, объявленная внутри объекта и тесно связанная с этим объектом. Предыдущая страница | Следующая страница |
|
Web дизайн: Бурлаков Михаил
Web программирование: Бурлаков Михаил