Пришло время
постижения ООП на Java. И, конечно же, вначале нужно понять, осознать
общую концепцию этого подхода к программированию. Я уже много раз ее
рассказывал, но не все ее сразу воспринимают. Сделаю еще одну попытку и поясню
общий принцип классов и объектов, придерживаясь конкретного примера.
Давайте
предположим, что перед нами поставили задачу создать простой графический
редактор, в котором пользователь может рисовать графические примитивы: линию,
треугольник, прямоугольник и эллипс:
Если бы в Java не было классов,
то нам пришлось бы хранить фигуры в памяти устройства в виде набора координат
вершин:
int N = 0;
int points_x[] = new int[100];
int points_y[] = new int[100];
// треугольник
points_x[0] = 10; points_y[0] = 5;
points_x[1] = 20; points_y[1] = 10;
points_x[2] = 5; points_y[2] = 10;
// линия
points_x[3] = 100; points_y[3] = 100;
points_x[4] = 200; points_y[4] = 50;
N = 5; // число вершин
Затем, например,
для перемещения треугольника, нужно было бы сначала найти его вершины и только
потом изменить его координаты. То же самое при изменении стиля линии: толщины и
цвета. Если бы современный инструментарий программиста ограничивался бы только
переменными и массивами, то лично я никогда бы не захотел быть программистом.
Написание масштабных приложений превратилось бы в пытку. Но как тогда можно
упростить программирование нашего примера? Вот здесь существенную помощью
оказывает ООП. Давайте посмотрим, как все поменяется в сравнении с
представлением на уровне массива.
Фундаментальным
элементом ООП является класс. И в нашем примере, можно объявить четыре класса
для каждого типа примитива: линии, треугольника, прямоугольника и эллипса.
Например, класс для треугольника в самом простом варианте можно записать так:
class Triangle {
int x1, x2, x3;
int y1, y2, y3;
int width, color;
}
Здесь за
ключевым словом class идет имя формируемого класса – Triangle (треугольник),
а внутри (в фигурных скобках) – набор необходимых переменных (их еще принято
называть полями класса, членами класса или просто – переменными класса). То
есть, мы создали общее описание треугольника в виде трех вершин, толщины линии
и цвета линии. Но вы можете заметить, что класс у нас один, а треугольников
может быть множество. Все верно. Дело в том, что класс следует воспринимать как
некий шаблон, чертеж, проект, по которому, затем, можно сформировать любое
количество конкретных объектов:
Triangle t1 = new Triangle();
Triangle t2 = new Triangle();
Triangle t3 = new Triangle();
Видите, у нас
теперь каждый треугольник представляется в виде целостного объекта, на которые
ссылаются отдельные переменные t1, t2, t3. И, далее, мы
уже работаем с ними через эти ссылки: меняем координаты вершин, толщину и цвет
линии. Все стало гораздо удобнее благодаря использованию классов.
По аналогии мы
можем объявить еще три класса с именами:
для
представления других типов графических примитивов. Но это только первый шаг в
понимании концепции ООП. Важно знать еще три фундаментальных момента (три
кита), на которых строится ООП:
Наследование классов
Сейчас мы
рассмотрим их на уровне идеи, а на последующих занятиях уже углубимся в
изучение этих понятий. Итак, что это за наследование? Снова вернемся к нашему
примеру с графическими примитивами и здесь можно заметить, что у всех их есть
общие свойства: толщина и цвет линии. Значит, чтобы не дублировать эту
информацию на уровне текста программы, можно все это вынести в отдельный класс,
допустим, с названием Properties и в нем определить эти общие
свойства:
А, далее, с
помощью механизма наследования образовывать дочерние классы, которые будут
включать все то, что определено в базовом классе Properties. Такой подход
позволяет исключать дублирование в тексте программы и следовать общепринятому
принципу:
DRY – Don’t Repeat Yourself
Причем, при
создании объектов классы Line, Triangle и остальные
будут представляться единым целым с базовым классом Properties. И, разумеется,
у каждого объекта будет своя копия этого базового класса.
В общем случае
механизм наследования можно воспринимать как расширение функциональности
базового класса через дочерние классы.
Инкапсуляция
Следующий кит
ООП носит «умное» название – инкапсуляция. Но за этим умным словом скрывается
очень простая идея: возможность скрывать внутри класса его элементы, чаще всего
– это переменные (поля) и функции (методы). Давайте конкретизируем этот момент.
Предположим, в классе Triangle имеется еще одна
переменная id – идентификатор
объекта. Это значение формируется в момент создания объекта и не должно в
последствии меняться. Для этого это поле id можно указать
скрытым и тогда доступ к нему извне класса будет невозможен:
То есть, мы
разрешаем использовать координаты объекта, но запрещаем обращаться к переменной
id. В этом и есть
смысл инкапсуляции: управление уровнем доступа к элементам класса. Конечно,
когда мы говорим «доступ», то подразумевается внешний доступ к переменным и
методам класса. Изнутри, любая функция по-прежнему может использовать все
имеющиеся элементы.
Подробнее об
этом механизме инкапсуляции мы будем говорить на последующих занятиях. Здесь
важно понять общий принцип: что это и для чего нужно.
Полиморфизм
Наконец, третий
кит, тоже с хитрым названием – полиморфизм. Понять его также довольно просто.
Вообще, полиморфизм в программировании можно воспринимать как возможность через
единый интерфейс получать доступ ко множеству реализаций:
В рамках ООП
полиморфизм часто проявляется в переопределении методов базового класса. Например,
в рамках нашего графического редактора в базовом классе Properties можно
определить метод draw(), который будет отвечать за рисование графических
примитивов. Затем, этот метод переопределить в дочерних классах и тогда,
вызывая draw() по ссылке на
базовый класс, будет вызываться переопределенный метод дочернего класса:
То есть, мы,
используя единый интерфейс – метод draw(), имеем
возможность рисовать самые разные графические примитивы. В этом сила третьего
кита под названием полиморфизм.
Вот эти три
момента: наследование, инкапсуляция и полиморфизм совместно с определением
классов и созданием объектов, образуют общую концепцию ООП. Эта концепция
соблюдается практически во всех современных языках программирования:
С++, С#, Python, Java
И популярность
этого подхода не случайна. Он существенно упрощает проектирование и разработку
больших приложений. А объектами могут быть самые разные элементы программы.
Фактически, класс – это фрагмент программы, который можно многократно
использовать и частично модифицировать под свои конкретные нужды. На этом
принципе основаны многочисленные библиотеки: начиная от обычных,
вычислительных, и заканчивая графическими и игровыми движками. Без ООП
современная разработка больших программ была бы куда сложнее и запутаннее. И,
конечно, далее на наших занятиях мы поближе познакомимся с миром классов и
объектов на примере языка Java.