ООП во FLASH 5

Настоящий Класс ( Class )


То, над чем мы будем работать - простенькая программка, позволяющая отображать фигуры и управлять ими. Хотя процесс создания OO-программы обычно включает в себя множество итераций и неудавшихся моделей, вы пытаетесь, до того как продолжите работу, выявить для себя проблему как можно яснее. Однако, дабы избегнуть нагромождения кода на первой же странице, давайте просто строить то, что строим, и по ходу дела добавлять то, что надо добавить. Терпение и труд, господа.

Итак, наша цель - программа управления фигурами, поэтому начнём с класса Фигур (Shape). На самом низком уровне наделим фигуры способностью двигаться и изменять размер. В псевдокоде (упрощённый код, предназначенный исключительно для людей, компьютер бы просто умер, попытайся его разгадать) это будет выглядеть примерно так:

// Shape Class ( класс Shape ) Shape(x,y,w,h) { // set x,y,w,h } // Свойства x,y,w,h // Методы Move(x,y); // переместить форму в позицию с координатами x y Size(w,h); // установить ширину в w, высоту в h // Теперь мы можем это использовать: s1 = new Shape( 10,20,30,40 ); s1.Move( 20, 30 ); s1.Size( 100, s1.y );

Однако остаются проблемы. А пока запомните одну важную вещь. Зарубите её себе на носу! (Если там ещё осталось место для памятных зарубок):

Когда создаётся класс, нужно предоставить пользователю возможно более простую, внутренне непротиворечивую, логичную структуру.

Даже в том случае, если вы будете единственным пользователем этого класса, задача остаётся такой же. Ведь когда придёт время использовать класс, у вас на уме наверняка будут уже совсем другие вещи, о которых до этого и не подозревали. А прочие пользователи созданного вами класса и вовсе не смогут (или не захотят) копаться в вашей голове. Выходит, код может компилироваться и работать, но при этом оставаться совершенно "неправильным". Хорошо срабатывает в таких случаях следующее правило: представьте, что с этим классом работаете вы сами. Разберём процедуру по шагам.

В чём проблема с первой строкой?

s1 = new Shape( 10,20,30,40 );


Первый очевидный вопрос: что обозначают все эти числа? Разумеется, можно поискать где-то вверху, но не забывайте, что между описанием класса и его использованием может быть достаточно большой кусок кода. А что будет, если добавить ещё несколько свойств - вращение, цвет, скос, имя?.. Следующий вопрос: что будет, если мы зададим ширину и высоту, а первые два параметра, x и y, оставим заданными по умолчанию? Если даже пользователь впишет null в необходимые позиции, значения установятся в 0, что может отличаться от значений по умолчанию. Другой вариант - передать лишь значения ширины и высоты, вновь создаёт проблему. Как объяснить классу Shape разницу между определением значений ширины, высоты и значений x и y? В конце концов, и те и другие всего лишь пары целых чисел. Это всё равно что, стоя на углу какой-нибудь улицы Ленина, гадать, в каком городе находитесь.

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

w = CreateWindow ("button","Click Me",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 100,100,50,50,hWnd, (HMENU) 100, ((LPCREATESTRUCT) lParam)->hInstance,NULL);

В то время, а ведь, возможно, всё это до сих пор хранится где-то глубоко в недрах ОС, видимо, так было нужно, ныне же нам гораздо приятнее смотреть на современный конструктор (взято из .NET, но подобным образом работает и Java, и KDE):

button1 = new Button(); button1.BackColor = SystemColors.Desktop; button1.Size = new Size (176, 56); button1.Location = new Point (168, 168); button1.Text = "Click Me";

Первый пример наглядно демонстрирует, почему атомные реакторы не работают под Windows 3.1. Пораскинув мозгами, из этого можно извлечь несколько полезных уроков. Во-первых, если серьёзных причин для усложнений системы нет, передавайте конструктору только те параметры, которые ему необходимы для создания объекта. Довольно заманчиво выглядит возможность разрешить пользователю передавать параметр Text как аргумент; но тогда почему Text должен быть важнее, чем, к примеру, Location; если же передаются оба параметра, то какой должен передаваться первым? И вообще, позволит ли нам передача этих параметров как аргументов сделать что-либо, кроме того, что задано жёстко (разве что людей запутать?). Короткий ответ: "Нет". Длинный ответ: "Этому не бывать!". Отсюда - правило: если параметр не нужен для создания объекта, не передавайте его в конструктор. (Чуть позже мы рассмотрим "перегрузку конструктора" - общепринятую, хотя и несколько противоречивую технологию, рассматривающую данную проблему с другой позиции.)



Прежде чем продолжить, взглянем ещё раз на вторую строку нашего кода:

s1.Move( 20, 30 );

Во-первых, что это означает? Что? Нужно ли переместиться в позицию с координатами 20, 30, или нужно сместиться на 20 единиц вправо и на 30 вниз? Узнать это можно лишь одним способом, найти в описании класса, который я вам навязал. Проверили? Нашли? Теперь же, найдя не только это, но и дорогу назад (забыв, правда, что там искали), вы, наконец, поняли, что первоначально это не было задано в классе. Прежде чем начать грязно ругаться, запомните, что большинство программ есть нечто большее, чем один-единственный класс и пара методов; для разумения принципов работы большинства методов недостаточно поверхностного взгляда. Даже если они отлично закомментированы (хе-хе!), мозгам придётся: во-первых, "сохранить информацию на диске", во-вторых, "включить поиск", затем - "пропарсить и сохранить на диск". И уже после всего этого - "найти необходимое место". Если ваше "сохранить на диск" подобно моему, то, к тому времени, когда дойдёте до конца логической цепочки, напрочь забудете, для чего переместили кнопку туда, где она находится сейчас. Как бы ни была великолепна фотографическая память, ей не справиться с семью последовательными элементами за семь секунд. Следовательно, нужно распрощаться с именами, допускающими неоднозначное толкование. Раз и навсегда.

На самом деле предполагалось, что метод переместит кнопку в позицию с указанными координатами, а не будет их использовать для относительного смещения. Откуда я это знаю? Ха! Да потому что Я это написал. Теперь я перепишу это так, чтобы вы тоже знали. Выберем более очевидный термин "Location" и продолжим.

s1.Location( 20, 30 );

Ну ладно, это всё еще выглядит ужасно, но, по крайней мере, мы теперь знаем, что это означает. Вы можете спросить, почему бы не написать просто так:

s1._x=20; s1._y=30;

А вот это действительно хороший вопрос. На который есть простой, но чересчур длинный ответ. Что-то типа: "Ну и когда же мы доберёмся до этой главы?"

<<

   ООП во Flash 5 ( II )    >>


Содержание раздела