Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 [ 153 ] 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

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

class A { function TestA() { ... } function Test() { ... }

class B { var $a; объект класса A

function B(параметры для A, другие параметры) { $a=new A(параметры для A); инициализируем другие поля B

function TestB() { ... } function Test() { ... }

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

Но вспомним, что мы хотели получить расширение возможностей класса A, а не нечто, содержащее объекты a. Что означает "расширение"? Лишь одно: мы бы хотели, чтобы везде, где допустима работа с объектами класса A, была допустима и работа с объектами класса B. Но в нашем примере это совсем не так.

□ Мы не видим явно, что класс B лишь расширяет возможности A, а не является отдельной сущностью.

□ Мы должны обращаться к "части a" класса B через $obj->a->TestA(), а к членам самого класса b как $obj->TestB(). Последнее может быть довольно утомительным, если, как это часто бывает, в B будет использоваться очень много методов из A и гораздо меньше - из B. Кроме того, это заставляет нас постоянно помнить о внутреннем устройстве класса B.

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

class B extends A { function В(параметры для А, другие параметры) { $this->A(параметры для A); инициализируем другие поля B



( Замечание

Немного о терминологии: принято класс A называть базовым, а класс в - производным от A. Иногда базовый класс также называют суперклассом, а производный - подклассом.

Зачем может понадобиться наследование? Например, мы написали класс Mysql-таблицы и хотели бы дополнительно иметь класс Guestbook (гостевая книга). Очевидно, в классе Guestbook будет много методов, которые нужны для того же, что и методы из MysqlTable, поэтому было бы разумным сделать его производным от

MysqlTable:

class Guestbook extends MysqlTable {

методы и свойства, которых нет в MysqlTable и которые относятся к гостевой книге

Многие языки программирования поддерживают множественное наследование (то есть такое, когда, скажем, класс B наследует члены не одного, а сразу нескольких классов - например, A и z). К сожалению, в PHP таких возможностей нет.

Полиморфизм

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

function TestB() { ... } function Test() { ... }

Ключевое слово extends говорит о том, что создаваемый класс является лишь "расширением" класса A, и не более того. То есть B содержит те же самые свойства и методы, что и A, но, помимо них и еще некоторые дополнительные, "свои".

Теперь "часть A" находится прямо внутри класса B и может быть легко доступна, наравне с методами и свойствами самого класса B. Например, для объекта $obj класса B допустимы вхражения $obj->TestA() и $obj->TestB(). Итак, мы видим, что, действительно, класс B является воплощением идеи "расширение функциональности класса A". Обратите также внимание: мы можем теперь забыть, что B унаследовал от A некоторые свойства или методы - снаружи все выглядит так, будто класс в реализует их самостоятельно.



Вернемся к нашему предыдущему примеру с классами A и B.

class A {

В1водит, функция какого класса б1ла вызвана function Test() { echo "Test from A\n"; } Тестовая функция - просто переадресует на Test() function Call() { Test(); }

class B extends A { Функция Test() для класса В function Test() { echo "Test from B\n"; }

$a=new A(); $b=new B();

Давайте рассмотрим следующие команды:

$a->Call(); напечатается "Test from A" $b->Test(); напечатается "Test from B" $b->Call(); Внимание! Напечатается "Test from B"!

Обратите внимание на последнюю строчку: вопреки ожиданиям, вызывается не функция Test() из класса A, а функция из класса в! Складывается впечатление, что Test() из в просто переопределила функцию Test() из А. Так оно на самом деле и есть. Функция, переопределяемая в производном классе, называется виртуальной.

Механизм виртуальных функций позволяет нам, например, "подсовывать" функциям, ожидающим объект одного класса, объект другого, производного, класса. Еще один классический пример - класс, воплощающий собой свойства геометрической фигуры, и несколько производных от него классов - квадрат, круг, треугольник и т. д. Базовый класс имеет виртуальную функцию Draw(), которая заставляет объект нарисовать самого себя. Все производные классы-фигуры, разумеется, переопределяют эту функцию (ведь каждую фигуру нужно рисовать по-особому). Также у нас есть массив фигур, причем мы не знаем, каких именно. Зато, используя полиморфизм, мы можем, не задумываясь, перебрать все элементы массива и вызвать для каждого из них метод Draw() - фигура сама "решит", какого она типа и как ее рисовать.

В нашем классе MysqlTable, который мы еще только-только наметили, идея полиморфизма найдет свое применение. И вот зачем. Мы проектируем класс так, чтобы другие классы, которые он будет использовать, подключали его к себе как производный. Тем самым они наследуют все свойства MysqlTable и добавляют некоторые свои. Например, класс Guestbook, реализующий гостевую книгу, может быть производным от MysqlTable и "расширять" его некоторыми дополнительными функциями - например, проверкой орфографии во введенном сообщении или же контролем, имеет ли право тот или иной пользователь писать в книгу (или он "отключен" за использование ненормативной лексики). Кроме того, прежде чем помещать данные в



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 [ 153 ] 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189