Анимация
JavaScript
|
Главная Библионтека Примечание Вроде бы понятно, не правда ли? А теперь давайте уберем все, кроме слов-связок, но оставим курсив. Вот что у нас получится. "Представим себе объект большого и сложного класса, например, MysqlTable, расположенный в оперативной памяти. Мы не хотим использовать свойства или методы объекта напрямую. Если уж быть честными, мы даже не можем напрямую использовать в программе этот объект - на него нет ссылок, и уж подавно не способны скопировать объект в другую переменную. Но зато, как мы знаем, его постоянно "сопровождают" объекты-интерфейсы, имеющие код небольшого размера. Эти интерфейсы могут передавать запросы на обслуживание - разумеется, из тех, для которых имеют соответствующие методы. Конечно, объект может иметь несколько разных интерфейсов. Важно то, что мы не можем напрямую использовать объект. При этом мы имеем право копировать объекты-интерфейсы - главному объекту нет до этого ровным счетом никакого дела. В PHP объект "не знает", сколько у него интерфейсов и как они используются". Итак, основная идея такова: отделим интерфейс MysqlTable от его реализации, т. е. напишем класс IMysql, с которым и будем всегда работать. Этот класс должен содержать все те методы, которые поддерживаются MysqlTable, только заниматься они будут ни чем иным, как просто переадресацией вызовов на "настоящие" объекты. А последние, в свою очередь, хранятся в глобальном массиве объектов, на элементы которого должно ссылаться одно из свойств IMysql. Реализуем эту стратегию для упрощенной версии MysqlTable, имеющей только метод Drop() и конструктор (листинг 31.5): i Листинг 31.5. Упрощенный интерфейс к таблице MySQL Массив объектов-таблиц, созданных в программе $GLOBALS["Tables"]=array(); вначале массив пуст Реализация класса. Это - об1чн1й класс без каких-либо особенностей. Давайте предположим, что объекты этого класса недопустимо копировать обычным способом. class MysqlTable { . . . function MysqlTable($name) { echo "MysqlTable($name)<br>"; } function Drop() { echo "Drop()<br>"; } Класс-интерфейс class IMysql { var $id; идентификатор реализации таблицы (MysqlTable) в $Tables Открывает таблицу с именем $name. Если эта таблица уже была открыта ранее, то ничего не делает и просто становится ее синонимом, иначе создает экземпляр объекта. function IMysql($name) { global $Tables; $this->id=$name; Если объект для таблица: $name еще не создан, создать его if(!isset($Tables[$name])) $Tables[$name]=new MysqlTable($name); Иначе объект уже существует и ничего делать не надо Уничтожает таблицу. Переадресуем вызов реализации function Drop() { $obj=&$GLOBALS[Tables][$this->id]; $obj->Drop(); } Демонстрация работы с интерфейсом $m=new IMysql("TestTable"); объект создается $m=new IMysql("TestTable"); нов1Й объект не создается! $m->Drop(); очищается единственный объект Примечание Откровенно говоря, мы реализовали здесь не совсем то, что в объектно-ориентированном проектировании принято называть "интерфейсом". По определению интерфейс не может иметь конструктора, класс же IMysql его имеет. Так что слово "интерфейс" здесь, мягко говоря, не подходит, но я буду называть класс iMysql именно так - для краткости. Думаю, в этом нет ничего страшного - такова уж специфика PHP, и это самое простое, что можно было бы предложить. В самом деле, не писать же на PHP специальные "классы-фабрики", занимающиеся исключительно созданием объектов, как это принято в ООП Таким образом, как при копировании, так и при создании объекта-таблицы, который был уже ранее создан в программе, новый экземпляр объекта не создается. Иными словами, мы можем иметь сколько угодно объектов класса IMysql, ссылающихся на одну и ту же таблицу, и при изменении одного из них это "почувствуют" и все остальные. Нужно только грамотно реализовать все переадресующие функции. И еще насчет класса-реализации: лучше всего дать ему какое-нибудь некрасивое имя (например, MysqlTableimpl ), чтобы какой-нибудь неопытный пользователь случайно не стал к нему обращаться напрямую, а не через IMysql. Хочу заметить, что в настоящих объектно-ориентированных языках нет причин прибегать к столь странным ухищрениям, потому что в них есть такое понятие, как указатель. В этих языках подобъект класса-интерфейса iMysql содержится прямо внутри объекта MysqlTable, и указатель на него можно получить либо посредством явных преобразований типов, либо с помощью специальных функций для "отпочко-вывания" интерфейса. Например, в COM+ эти функции часто называют Queryinterface(). Здесь же у нас вышло нечто вроде примитивной поддержки указателей (ведь объект класса IMysql именно указывает на "хозяина" типа MysqlTable, но не содержит его в себе!), которых в PHP нет. Правда, получилось все это несколько неказисто (уж очень некрасивы и одинаковы функции переадресации...), зато механизм действительно работает и решает все поставленные задачи. 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 |