Читаем Программирование полностью

  Какие возможности обеспечивают эти двенадцать дополнительных функций-членов и два канала доступа к спецификациям (private: и protected:)? Главный ответ состоит в том, что защита класса от нежелательного изменения позволяет разработчику создавать лучшие классы с меньшими усилиями. Этот же аргумент относится и к инвариантам (см. раздел 9.4.3). Подчеркнем эти преимущества на примере определения классов, производных от класса Shape. В более ранних вариантах класса Shape мы использовали следующие переменные:


Fl_Color lcolor;

int line_style;


Оказывается, это очень ограничивает наши возможности (стиль линии, задаваемый переменной типа int, не позволяет элегантно задавать ширину линии, а класс Fl_Color не предусматривает невидимые линии) и приводит к довольно запутанному коду. Если бы эти две переменные были открытыми и использовались в пользовательской программе, то мы могли бы улучшить интерфейсную библиотеку только за счет взлома этого кода (поскольку в нем упоминаются имена lcolor и line_style).

  Кроме того, функции доступа часто обеспечивают удобство обозначений. Например, инструкция s.add(p) читается и записывается легче, чем s.points.push_back(p)

14.2.3. Рисование фигур

Мы описали почти все, кроме ядра класса Shape.


void draw() const; // работает с цветом и вызывает функцию

                   // draw_lines

virtual void draw_lines() const; // рисует линии


Основная задача класса Shape — рисовать фигуры. Мы не можем удалить из класса Shape все остальные функции и оставить его вообще без данных о нем самом, не нанеся вреда нашей основной концепции (см. раздел 14.4); рисование — это главная задача класса Shape. Он выполняет ее с помощью библиотеки FLTK и операционной системы, но с точки зрения пользователя он выполнят только две функции.

• Функция draw() интерпретирует стиль и цвет, а затем вызывает функцию draw_lines().

• Функция draw_lines() подсвечивает пиксели на экране.


Функция draw() не использует никаких новаторских методов. Она просто вызывает функции библиотеки FLTK, чтобы задать цвет и стиль фигуры, вызывает функцию draw_lines(), чтобы выполнить реальное рисование на экране, а затем пытается восстановить цвет и фигуру, заданные до ее вызова.


void Shape::draw() const

{

  Fl_Color oldc = fl_color();

  // универсального способа идентифицировать текущий стиль

  // не существует

  fl_color(lcolor.as_int());            // задаем цвет

  fl_line_style(ls.style(),ls.width()); // задаем стиль

  draw_lines();

  fl_color(oldc);   // восстанавливаем цвет (предыдущий)

  fl_line_style(0); // восстанавливаем стиль линии (заданный

                    // по умолчанию)

}


  К сожалению, в библиотеке FLTK не предусмотрен способ идентификации текущего стиля, поэтому он просто устанавливается по умолчанию. Это пример компромисса, на который мы иногда идем, чтобы обеспечить простоту и мобильность программы. Мы не думаем, что эту функциональную возможность стоит реализовать в нашей интерфейсной библиотеке.

  Обратите внимание на то, что функция Shape::draw() не работает с цветом заливки фигуры и не управляет видимостью линий. Эти свойства обрабатывают отдельные функции draw_lines(), которые лучше “знают”, как их интерпретировать. В принципе всю обработку цвета и стиля можно было бы перепоручить отдельным функциям draw_lines(), но для этого пришлось бы повторять много одних и тех же фрагментов кода.

Рассмотрим теперь, как организовать работу с функцией draw_lines(). Если немного подумать, то можно прийти к выводу, что функции-члену класса Shape было бы трудно рисовать все, что необходимо для создания любой разновидности фигуры. Для этого пришлось бы хранить в объекте класса Shape каждый пиксель каждой фигуры. Если мы используем вектор vector, то вынуждены хранить огромное количество точек. И что еще хуже, экран (т.е. устройство для вывода графических изображений) лучше “знает”, как это делать.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже