Программирование на Java
Шрифт:
//вызов метода draw в случае,
// если ячейка не пустая.
if(p[i]!=null) p[i].draw;
}
for(int i = 0; i < l.length;i++) {
if(l[i]!=null) l[i].draw;
}
for(int i = 0; i < c.length;i++) {
if(c[i]!=null) c[i].draw;
}
for(int i = 0; i < b.length;i++) {
if(b[i]!=null) b[i].draw;
}
...
Недостатком написанного выше кода является дублирование практически идентичного кода для отображения каждого типа примитивов. Также неудобно то, что при дальнейшей модернизации нашего графического редактора и добавлении возможности рисовать новые типы графических примитивов, например Text, Star и т.д., при
Используя полиморфизм, мы можем значительно упростить реализацию подобной функциональности. Прежде всего, создадим общий родительский класс для всех наших классов. Пусть таким классом будет Point. В результате получим иерархию классов, которая изображена на рисунке 2.3.
У каждого из дочерних классов метод draw переопределен таким образом, чтобы отображать экземпляры каждого класса соответствующим образом.
Для описанной выше иерархии классов, используя полиморфизм, можно написать следующий код:
...
Point p[] = new Point[1000];
p[0] = new Circle;
p[1] = new Point;
p[2] = new Box;
p[3] = new Line;
... for(int i = 0; i < p.length;i++) {
if(p[i]!=null) p[i].draw;
}
...
В описанном выше примере массив p[] может содержать любые объекты, порожденные от наследников класса Point. При вызове какого-либо метода у любого из элементов этого массива будет выполнен метод того объекта, который содержится в ячейке массива. Например, если в ячейке p[0] находится объект Circle, то при вызове метода draw следующим образом:
p[0].draw
нарисуется круг, а не точка.
В заключение приведем формальное определение полиморфизма.
Полиморфизм (polymorphism) - положение теории типов, согласно которому имена (например, переменных) могут обозначать объекты разных (но имеющих общего родителя) классов. Следовательно, любой объект, обозначаемый полиморфным именем, может по-своему реагировать на некий общий набор операций [2].
В процедурном программировании тоже существует понятие полиморфизма, которое отличается от рассмотренного механизма в ООП. Процедурный полиморфизм предполагает возможность создания нескольких процедур или функций с одним и тем же именем, но разным количеством или различными типами передаваемых параметров. Такие одноименные функции называются перегруженными, а само явление - перегрузкой ( overloading ). Перегрузка функций существует и в ООП и называется перегрузкой методов.
Рис. 2.3. Пример иерархии классов.
Примером использования перегрузки методов в языке Java может служить класс PrintWriter, который применяется, в частности, для вывода сообщений на консоль. Этот класс имеет множество методов println, которые различаются типами и/или количеством входных параметров. Вот лишь несколько из них:
void println
// переход на новую строку
void println(boolean x)
// выводит значение булевской
// переменной (true или false)
void println(String x)
// выводит строку - значение
// текстового параметра.
Определенные сложности возникают при вызове перегруженных методов. В Java существуют специальные правила, которые позволяют решать эту проблему. Они будут рассмотрены в соответствующей лекции.
Типы отношений между классами
Как
Возможны следующие связи между классами в рамках объектной модели (приводятся лишь наиболее простые и часто используемые виды связей, подробное их рассмотрение выходит за рамки этой ознакомительной лекции):
* агрегация ( Aggregation );
* ассоциация ( Association );
* наследование ( Inheritance );
* метаклассы ( Metaclass ).
Агрегация
Отношение между классами типа "содержит" (contain) или "состоит из" называется агрегацией, или включением. Например, если аквариум наполнен водой и в нем плавают рыбки, то можно сказать, что аквариум агрегирует в себе воду и рыбок.
Такое отношение включения, или агрегации (aggregation), изображается линией с ромбиком на стороне того класса, который выступает в качестве владельца, или контейнера. Необязательное название отношения записывается посередине линии.
В нашем примере отношение contain является двунаправленным. Объект класса Aquarium содержит несколько объектов Fish. В то же время каждая рыбка "знает", в каком именно аквариуме она живет. Каждый класс имеет свою роль в агрегации, которая указывает, какое место занимает класс в данном отношении. Имя роли не является обязательным элементом обозначений и может отсутствовать на диаграмме. В примере можно видеть роль home класса Aquarium (аквариум является домом для рыбок), а также роль inhabitants класса Fish (рыбки являются обитателями аквариума). Название роли обычно совпадает с названием соответствующего поля в классе. Изображение такого поля на диаграмме излишне, если уже указано имя роли. Т.е. в данном случае класс Aquarium будет иметь свойство (поле) inhabitants, а класс Fish - свойство home.
Число объектов, участвующих в отношении, записывается рядом с именем роли. Запись " 0..n " означает "от нуля до бесконечности". Приняты также обозначения:
" 1..n " - от единицы до бесконечности;
" 0 " - ноль;
" 1 " - один;
" n " - фиксированное количество;
" 0..1 " - ноль или один.
Код, описывающий рассмотренную модель и явление агрегации, может выглядеть, например, следующим образом:
// определение класса Fish
public class Fish {
// определения поля home
// (ссылка на объект Aquarium)
private Aquarium home;
public Fish {
}
}
// определение класса Aquarium
public class Aquarium {
// определения поля inhabitants
// (массив ссылок на объекты Fish)
private Fish inhabitants[];
public Aquarium {
}
}
Ассоциация
Если объекты одного класса ссылаются на один или более объектов другого класса, но ни в ту, ни в другую сторону отношение между объектами не носит характера "владения", или контейнеризации, такое отношение называют ассоциацией (association). Отношение ассоциации изображается так же, как и отношение агрегации, но линия, связывающая классы,- простая, без ромбика.