Java COURSE Lec02
Java COURSE Lec02
Java COURSE Lec02
Лекция 2. Основы
объектно-ориентированного
программирования
27 апреля 2003 года
Авторы документа:
Николай Вязовик (Центр Sun технологий МФТИ) <vyazovick@itc.mipt.ru> Евгений Жилин (Центр Sun
технологий МФТИ) < gene@itc.mipt.ru>
Copyright © 2003 года Центр Sun технологий МФТИ,ЦОС и ВТ МФТИ®, Все права защищены. Аннотация
В этой лекции излагаются основные концепции Объектно-Оринетированного Подхода (ООП) к
проектированию программного обеспечения. Поскольку в Java почти все типы (за исключением 8
простейших) являются объектными, владение ООП становится необходимым условием для успешного
применения языка. Лекция имеет вводный, обзорный характер. Для более детального изучения
предлагается список дополнительной литературы и Интернет-ресурсов.
Rendered by www.RenderX.com
ii
Оглавление
Лекция 2. Основы объектно-ориентированного программирования.............................1
1. Основы объектно-ориентированного программирования...........................................1
1.1. Методология процедурно-ориентированного программирования...................1
1.2. Методология объектно-ориентированного программирования........................4
1.3. Объекты................................................................................................................5
1.3.1. Состояние.....................................................................................................6
1.3.2. Поведение....................................................................................................6
1.3.3. Уникальность...............................................................................................7
1.4. Классы...................................................................................................................7
1.4.1. Инкапсуляция................................................................................................8
1.4.2. Полиморфизм...............................................................................................9
1.5. Типы отношений между классами.....................................................................12
1.5.1. Агрегация...................................................................................................12
1.5.2. Ассоциация................................................................................................13
1.5.3. Наследование............................................................................................14
1.5.4. Метаклассы................................................................................................15
1.6. Достоинства ООП...............................................................................................16
1.7. Недостатки ООП.................................................................................................. 17
1.8. Заключение...........................................................................................................18
1.9. Контрольные вопросы..........................................................................................19
Программирование на Java
Rendered by www.RenderX.com
Методология процедурно-ориентированного программирования
Стр. 3 из 24
Модель содержит не все признаки и свойства представляемого ею предмета или понятия, а только те,
которые существенны для разрабатываемой программной системы. Тем самым модель "беднее", а,
следовательно, проще представляемого ею предмета или понятия.
Простота модели по отношению к реальному предмету позволяет сделать ее формальной. Благодаря
такому характеру моделей при разработке можно четко выделить все зависимости и операции над ними в
создаваемой программной системе. Это упрощает как разработку и изучение (анализ) моделей, так и их
реализацию на компьютере.
Объектно-ориентированный подход помогает справиться с такими сложными проблемами, как
• уменьшение сложности программного обеспечения;
• повышение надежности программного обеспечения;
• обеспечение возможности модификации отдельных компонентов программного обеспечения без
изменения остальных его компонентов.
• обеспечение возможности повторного использования отдельных компонентов программного
обеспечения.
Более детально преимущества и недостатки объектно-ориентированного программирования будут
рассмотрены в конце главы, так как для их понимания необходимо знание основных понятий и положений
ООП.
Систематическое применение объектно-ориентированного подхода позволяет разрабатывать хорошо
структурированные, надежные в эксплуатации, достаточно просто модифицируемые программные
системы. Этим объясняется интерес программистов к объектно-ориентированному подходу и объектно-
ориентированным языкам программирования. ООП является одним из наиболее интенсивно
развивающихся направлений теоретического и прикладного программирования.
1.3. Объекты
По определению будем называть объектом понятие, абстракцию или любой предмет с четко очерченными
границами, имеющую смысл в контексте рассматриваемой прикладной проблемы. Введение объектов
преследует две цели:
• понимание прикладной задачи (проблемы);
• введение основы для реализации на компьютере.
Программирование на Java
Rendered by www.RenderX.com
Стр. 8 из 24
Основы объектно-ориентированного программирования
Примеры объектов: форточка, Банк "Империал", Петр Сидоров, дело № 7461, сберкнижка и т.д.
Каждый объект имеет определенное время жизни. В процессе выполнения программы или
функционирования какой-либо реальной системы могут создаваться новые объекты и уничтожаться уже
существующие.
Гради Буч дает следующее определение объекта:
Объект - это мыслимая или реальная сущность, обладающая характерным поведением, отличительными
характеристиками и являющаяся важной в предметной области.[1]
Каждый объект имеет состояние, обладает некоторым хорошо определенным поведением и уникальной
идентичностью.
1.3.1. Состояние.
Рассмотрим пример. Любой человек может находиться в некотором положении (состоянии) стоять,
сидеть, лежать, и в то же время совершать какие либо действия.
Например, человек может прыгать, если он стоит, и не может - если он лежит, для этого ему потребуется
сначала встать. Также в объектно-ориентированном программировании состояние объекта может
определяться наличием или отсутствием связей между моделируемым объектом и другими объектами.
Более подробно все возможные связи между объектами будут рассмотрены в разделе Типы отношений
между классами.
Например, если у человека есть удочка (у него есть связь с объектом Удочка), то он может ловить рыбу, а
если удочки нет, то такое действие невозможно. Из этих примеров видно, что набор действий, которые
может совершать человек, зависит от параметров объекта, который его моделирует.
Для рассмотренных выше примеров такими характеристиками, или атрибутами, объекта Человек
являются:
• текущее положение человека (стоит, сидит, лежит);
• наличие удочки (есть или нет).
В конкретной задаче могут появиться и другие свойства, например, физическое состояние, здоровье
(больной человек обычно не прыгает).
Состояние (state) - совокупный результат поведения объекта: одно из стабильных условий, в которых
объект может существовать, охарактеризованных количественно; в любой конкретный момент времени
состояние объекта включает в себя перечень (обычно, статический) свойств объекта и текущие значения
(обычно, динамические) этих свойств.
[1]
1.3.2. Поведение
Каждый объект имеет определенный набор действий, которые с ним можно произвести. Например,
возможные действия с некоторым файлом операционной системы ПК:
• создать
• открыть
• читать из файла
Программирование на Java
Rendered by www.RenderX.com
Классы
Стр. 9 из 24
• писать в файл
• закрыть
• удалить
Результат выполнения действий зависит от состояния объекта на момент совершения действия, т.е.
нельзя, например, удалить файл, если он открыт кем-либо (заблокирован). В то же время действия могут
менять внутреннее состояние объекта - при открытии или закрытии файла свойство "открыт" принимает
значения "да" или "нет" соответственно.
Программа, написанная с использованием ООП, обычно состоит из множества объектов, и все эти
объекты взаимодействуют между собой. Обычно говорят, что взаимодействие между объектами в
программе происходит посредством передачи сообщений между ними.
В терминологии объектно-ориентированного подхода понятия "действие", "сообщение" и "метод" являются
синонимами. Т.е. выражения "выполнить действие над объектом", "вызвать метод объекта" и "послать
сообщение объекту для выполнения какого-либо действия" эквивалентны. Последняя фраза появилась из
следующей модели. Программу, построенную по технологии ООП, можно представить себе как
виртуальное пространство, заполненное объектами, которые условно "живут" некоторой жизнью. Их
активность проявляется в том, что они вызывают друг у друга методы, или посылают друг другу
сообщения. Внешний интерфейс объекта, или набор его методов, это описание, какие сообщения он
может получать.
Поведение (behavior) - действия и реакции объекта, выраженные в терминах передачи сообщений и
изменения состояния; видимая извне и воспроизводимая активность объекта.
[1]
1.3.3. Уникальность
Уникальность - это то, что отличает один объект от других. Например, у вас может быть несколько
абсолютно одинаковых монет, даже если абсолютно все их свойства (атрибуты) одинаковы (год выпуска,
номинал и.д.) и при этом вы можете использовать их независимо друг от друга - они по-прежнему
остаются разными монетами.
В машинном представлении под параметром уникальности объекта наиболее часто понимается адрес
размещения объекта в памяти.
Identity (уникальность) объекта состоит в том, что всегда возможно определить, указывают ли две ссылки
на один и тот же объект, или на разные объекты. При этом два объекта могут во всем быть похожими, их
образ в памяти может представляться одинаковыми последовательностями байтов, но, тем не менее, их
Identity может быть различна.
Наиболее распространенной ошибкой является понимание уникальности как имя ссылки на объект. Это
не верно, т.к. на один объект могут указывать несколько ссылок и ссылки могут менять свои значения
(ссылаться на другие объекты) за время своего существования.
Итак, уникальность (identity) - природа объекта; то, что отличает его от других объектов.[1]
1.4. Классы
Все монеты из предыдущего примера принадлежат одному и тому же классу объектов (именно с этим
связана их одинаковость). Номинальная стоимость монеты, металл, из которого она изготовлена, форма -
это атрибуты класса: совокупность атрибутов и их
Программирование на Java
Rendered by www.RenderX.com
Стр. 10 из 24
Основы объектно-ориентированного программирования
значений характеризует объект. Наряду с термином "атрибут" часто используют термины "свойство" и
"поле", которые в объектно-ориентированном программировании являются синонимами.
Все объекты одного и того же класса описываются одинаковыми наборами атрибутов. Однако
объединение объектов в классы определяется не наборами атрибутов, а семантикой. Так, например,
объекты конюшня и лошадь могут иметь одинаковые атрибуты: цена и возраст. При этом они могут
относиться к одному классу, если рассматриваются в задаче просто как товар, либо к разным классам,
если в рамках поставленной задачи они будут использоваться различными способами, т.е. над ними будут
совершаться различные действия.
Объединение объектов в классы позволяет рассмотреть задачу в более общей постановке. Класс имеет
имя (например, лошадь), которое относится ко всем объектам этого класса. Кроме того, в классе вводятся
имена атрибутов, которые определены для объектов. В этом смысле описание класса аналогично
описанию типа структуры или записи (record), которые широко применяются в процедурном
программировании; при этом каждый объект имеет тот же смысл, что и экземпляр структуры (переменная
или константа соответствующего типа).
Формально класс - шаблон поведения объектов определенного типа с определенными параметрами,
определяющими состояние. Все экземпляры одного класса (объекты, порожденные от одного класса)
• Имеют один и тот же набор свойств
• Общее поведение, одинаково реагируют на одинаковые сообщения
В соответствии с UML (Unified Modeling Language, унифицированный язык моделирования) класс имеет
следующее графическое представление:
Класс изображается в виде прямоугольника, состоящего из трех частей. В верхней части помещается
название класса, в средней - свойства объектов класса, в нижней - действия, которые можно выполнять с
объектами данного класса (методы).
Каждый класс может также иметь специальные методы, которые автоматически вызываются при создании
и уничтожении объектов этого класса:
• конструктор (constructor) - выполняется при создании объектов;
• деструктор (destructor) - выполняется при уничтожении объектов;
Обычно конструктор и деструктор имеют специальный синтаксис, который может отличаться от
синтаксиса, используемого для написания обычных методов класса.
1.4.1. Инкапсуляция
Инкапсуляция (encapsulation) - это сокрытие реализации класса и отделение его внутреннего
представления от внешнего (интерфейса). При использовании объектно-ориентированного подхода не
принято использовать прямой доступ к свойствам какого-либо класса из методов других классов. Для
доступа к свойствам класса принято использовать специальные методы этого класса для получения и
изменения его свойств.
Внутри объекта данные и методы могут обладать различной степенью открытости (или доступности).
Степени доступности, принятые в языке Java, подробно будут рассмотрены в более поздних главах. Они
позволяют более тонко управлять свойством инкапсуляции.
Программирование на Java
Rendered by www.RenderX.com
Классы
Стр. 11 из 24
Открытые члены класса составляют внешний интерфейс объекта. Эта та функциональность, которая
доступна другим классам. Закрытыми обычно объявляются все свойства класса, а так же
вспомогательные методы, которые являются деталями реализации и от которых не должны зависеть
другие части системы.
Благодаря сокрытию реализации за внешним интерфейсом класса можно менять внутреннюю логику
отдельного класса, не меняя код остальных компонентов системы.
Обеспечение доступа к свойствам класса только через его методы также дает ряд преимуществ. Во-
первых, так гораздо проще контролировать корректные значения полей, ведь прямое обращение к
свойствам отслеживать невозможно, а значит им могут присвоить некорректные значения.
Во-вторых, не составит труда изменить способ хранения данных. Если информация станет храниться не в
памяти, а в долговременном хранилище, таком как файловая система или база данных, то потребуется
изменить лишь ряд методов одного класса, а не вводить эту функциональность во все части системы.
Наконец, программный код, написанный с использованием этого принципа легче отлаживать. Для того
чтобы узнать, в какой момент времени и кто изменил свойство интересующего нас объекта, достаточно
добавить вывод отладочной информации в тот метод объекта, посредством которого осуществляется
доступ к свойству этого объекта. При использовании прямого доступа к свойствам объектов программисту
бы пришлось добавлять вывод отладочной информации во все участки кода, где используется
интересующий нас объект.
1.4.2. Полиморфизм
Полиморфизм является одним из фундаментальных понятий в объектно-ориентированном
программировании наряду с наследованием и инкапсуляцией. Слово полиморфизм греческого
происхождения и означает "имеющий много форм". Чтобы понять, что означает полиморфизм
применительно к объектно-ориентированному программированию, рассмотрим пример.
Предположим мы хотим написать векторный графический редактор, в котором опишем в виде классов
набор графических примитивов - Point, Line, Circle, Box, и т.д. У каждого из этих классов определим метод
draw для отображения соответствующего примитива на экране.
Очевидно, придется написать некоторый код, который при необходимости отобразить рисунок будет
последовательно перебирать все примитивы, которые на момент отрисовки находятся на экране, и
вызывать метод draw у каждого из них. Человек, незнакомый с полиморфизмом, вероятнее всего создаст
несколько массивов: отдельный массив для каждого типа примитивов и напишет код, который
последовательно переберет элементы из каждого массива и вызовет у каждого элемента метод draw. В
результате получится примерно следующий код:
//создание пустого массива, который может содержать //объекты Point с
максимальным объемом 1000 Point[] p = new Point[1000];
Line[] l = new Line[1000];
Программирование на Java
Rendered by www.RenderX.com
Стр. 12 из 24
Основы объектно-ориентированного программирования
Circle[] c = new Circle[1000]; Box[] b = new Box[1000];
// предположим, в этом месте происходит заполнение всех массивов //
соответствующими объектами
for(int i = 0; i < p.length;i++){ //цикл с перебором всех ячеек массива. //вызов
метода draw() в случае, // если ячейка не пустая. if(p[i]!=null) p.draw();
}
for(int i = 0; i < l.length;i++){ if(l[i]!=null) l.draw();
}
for(int i = 0; i < c.length;i++){ if(c[i]!=null) c.draw();
}
for(int i = 0; i < b.length;i++){
if(b[i]!=null) b.draw();
}
Недостатком написанного выше кода является дублирование практически идентичного кода для
отображения каждого типа примитивов. Также неудобно то, что при дальнейшей модернизации нашего
графического редактора и добавлении возможности рисовать новые типы графических примитивов,
например Text, Star и т.д., при таком подходе придется менять уже существующий код и добавлять в него
определения новых массивов, а также обработку элементов, содержащихся в них.
Используя полиморфизм, мы можем значительно упростить реализацию подобной функциональности.
Прежде всего, создадим общий родительский класс для всех наших классов. Пусть таким классом будет
класс Point. В результате получим иерархию классов, которая изображена на рисунке (1.3).
У каждого из дочерних классов метод draw переопределен таким образом, чтобы отображать экземпляры
каждого класса соответствующим образом.
Программирование на Java
Rendered by www.RenderX.com
Классы
Стр. 13 из 24
Для описанной выше иерархии классов, используя полиморфизм, можно написать следующий код:
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.draw();
}
В описанном выше примере массив p[] может содержать любые объекты, порожденные от наследников
класса Point. При вызове какого-либо метода у любого из элементов этого массива будет выполнен метод
того объекта, который содержится в ячейке массива. Например, если в ячейке p[0] находится объект
Circle, то при вызове метода draw следующим образом
p[0].draw()
нарисуется круг, а не точка.
В заключение приведем формальное определение полиморфизма:
Полиморфизм (polymorphism) - положение теории типов, согласно которому имена (например,
переменных) могут обозначать объекты разных (но имеющих общего родителя) классов. Следовательно,
любой объект, обозначаемый полиморфным именем, может по-своему реагировать на некий общий набор
операций[1].
В процедурном программировании тоже существует понятие полиморфизма, которое отличается от
рассмотренного механизма в ООП. Процедурный полиморфизм предполагает возможность создания
нескольких процедур или функций с одинаковым именем, но разными количеством или типами
передаваемых параметров. Такие одноименные функции называются перегруженными, а само явление -
перегрузкой (overloading). Перегрузка функций существует и в ООП и называется перегрузкой методов.
Примером использования перегрузки методов в языке Java может служить класс PrintWriter, который
используется в частности для вывода сообщений на консоль. Этот класс имеет множество методов println,
которые различаются типами и/или количеством входных параметров. Вот лишь несколько из них:
void println() // переход на новую строку
// выводит значение булевской переменной (true или false) void println(boolean x)
void println(String x) // выводит строку - значение текстового параметра
Программирование на Java
Rendered by www.RenderX.com
Стр. 14 из 24
Основы объектно-ориентированного программирования
Определенные сложности возникают при вызове перегруженных методов. В Java существуют
специальные правила, которые решают эту проблему. Они будут рассмотрены в соответствующей главе.
1.5. Типы отношений между классами
Как правило, любая программа, написанная на объектно-ориентированном языке, представляет собой
некоторый набор классов, связанных между собой. Можно провести аналогию между строительством
дома и написанием программы. Подобно тому, как здание строится из кирпичей, компьютерная программа
с использованием ООП строится из классов. Причем эти классы должны знать друг о друге, для того
чтобы взаимодействовать между собой и сообща выполнить поставленную задачу.
Возможны следующие связи между классами в рамках объектной модели (приводятся лишь наиболее
простые и часто используемые виды связей, подробное их рассмотрение выходит за рамки этой
ознакомительной главы):
• Агрегация (Aggregation)
• Ассоциация (Association)
• Наследование (Inheritance)
• Метаклассы (Metaclass)
1.5.1. Агрегация
Отношение между классами типа "содержит" или "состоит из" называется агрегацией или включением.
Например, если аквариум наполнен водой и в нем плавают рыбки, то можно сказать, что аквариум
агрегирует в себе воду и рыбок.
Такое отношение включения или агрегации (aggregation) изображается линией с ромбиком на стороне того
класса, который выступает в качестве владельца или контейнера. Необязательное название отношения
записывается посередине линии.
В нашем примере отношение "contain" является двунаправленным. Объект класса Aquarium содержит
несколько объектов Fish. В то же время каждая рыбка "знает", в каком именно аквариуме она живет. Факт
участия класса в отношении изображается посредством роли. В примере можно видеть роль "home"
класса Aquarium (аквариум является домом для рыбок), а также роль "inhabitants" класса Fish (рыбки
являются обитателями аквариума). Название роли обычно совпадает с названием соответствующего поля
в классе. Изображение такого поля на диаграмме излишне, если уже изображено имя роли. Т.е. в данном
случае класс Aquarium будет иметь свойство (поле) inhabitants, а класс Fish -свойство home.
Число объектов, участвующих в отношении, записывается рядом с именем роли. Запись "0..n" означает
"от нуля до бесконечности". Приняты так же обозначения:
• "1..n" - от единицы до бесконечности;
• "0" - ноль;
• "1" - один;
• "n" - фиксированное количество;
Программирование на Java
Rendered by www.RenderX.com
Типы отношений между классами
Стр. 15 из 24
• "0..1" - ноль или один.
Код, описывающий рассмотренную модель и явление агрегации, может выглядеть, например, следующим
образом:
// определение класса Fish public class Fish {
// определения поля home (ссылка на объект Aquarium) private Aquarium home;
public Fish() { }
}
// определение класса Aquarium public class Aquarium {
// определения поля inhabitants (массив ссылок на объекты Fish) private Fish
inhabitants[];
public Aquarium() { }
}
1.5.2. Ассоциация
Если объекты одного класса ссылаются на один или более объектов другого класса, но ни в ту, ни в
другую сторону отношение между объектами не носит характера "владения" или контейнеризации, то
такое отношение называют ассоциацией (association). Отношение ассоциации изображается так же,как и
отношение агрегации, но линия, связывающая классы - простая, без ромбика.
В качестве примера можно рассмотреть программиста и его компьютер. Между этими двумя объектами
нет агрегации, но существует четкая взаимосвязь. Так, всегда можно установить за какими компьютерами
работает какой-либо программист, а также какие люди пользуются отдельно взятым компьютером. В
рассмотренном примере имеет место ассоциация многие-ко-многим.
В данном случае между экземплярами классов Programmer и Computer в обе стороны используется
отношение "0..n", т.к. программист теоретически может не пользоваться компьютером (если он теоретик
или на пенсии). В свою очередь компьютер может никем не использоваться (если он новый и еще не
установлен).
Код, соответствующий рассмотренному примеру, будет, например, следующим:
public class Programmer {
private Computer computers[];
public Programmer() { }
Программирование на Java
Rendered by www.RenderX.com
Стр. 16 из 24
Основы объектно-ориентированного программирования
}
public class Computer {
private Programmer programmers[];
public Computer() { }
}
1.5.3. Наследование
Наследование (inheritance) - это отношение между классами, при котором класс использует структуру или
поведение другого (одиночное наследование) или других (множественное наследование) классов.
Наследование вводит иерархию "общее/частное", в которой подкласс наследует от одного или нескольких
более общих суперклассов. Подклассы обычно дополняют или переопределяют унаследованную
структуру и поведение.
В качестве примера можно рассмотреть задачу, в которой необходимо реализовать классы "Легковой
автомобиль" и "Грузовой автомобиль". Очевидно, эти два класса имеют много общей функциональности.
Так, оба они имеют 4 колеса, двигатель, могут перемещаться и т.д. Всеми этими свойствами обладает
любой автомобиль, не зависимо от того грузовой он или легковой, 5- или 12-местный. Разумно вынести
эти общие свойства и функциональность в отдельный класс, например "Автомобиль", и наследовать от
него классы "Легковой автомобиль" и "Грузовой автомобиль" чтобы избежать повторного написания
одного и того же кода в разных классах.
Отношение обобщения обозначается сплошной линией с треугольной стрелкой на одном из концов.
Стрелка указывает на более общий класс (класс-предок или суперкласс), а ее отсутствие - на более
специальный класс (класс-потомок или подкласс)
Использование наследования способствует уменьшению количества кода, написанного для описания
схожих сущностей, а так же способствует написанию более эффективного и гибкого кода.
В рассмотренном примере применено одиночное наследование. Некоторый класс так же может
наследовать свойства и поведение сразу нескольких классов. Наиболее популярным примером
применения множественного наследования является проектирование системы учета товаров в
зоомагазине.
Все животные в зоомагазине являются наследниками класса "Животное", а также наследниками класса
"Товар". Т.е. все они имеют возраст, нуждаются в пище и воде, и в то же время имеют цену и могут быть
проданы.
Множественное наследование на диаграмме изображается точно так же как и одиночное наследование за
исключением того, что линии наследования соединяют класс-потомок сразу с несколькими
суперклассами.
Не все объектно-ориентированные языки программирования содержат в себе языковые конструкции для
описания множественного наследования.
Многие объектно-ориентированные языки программирования не поддерживают множественное
наследование и не имеют синтаксических конструкций для его реализации.
Программирование на Java
Rendered by www.RenderX.com
Типы отношений между классами
Стр. 17 из 24
В языке Java множественное наследование имеет ограниченную поддержку через интерфейсы и будет
рассмотрено в следующих главах.
1.5.4. Метаклассы
Итак, любой объект имеет структуру, состоящую из полей и методов. Объекты, имеющие одинаковую
структуру и семантику, описываются одним классом, который и является, по сути, определением
структуры объектов, порожденных от него.
В свою очередь каждый класс, или описание, всегда имеет строгий шаблон, задаваемый языком
программирования или выбранной объектной моделью. Он определяет, например, допустимо ли
множественное наследование, какие ограничения на именование классов, как описываются п^оля и
методы, набор существующих типов данных и многое другое. Таким образом, класс можно рассматривать
как объект, у которого есть свойства (имя, список полей и их типы, список методов, список аргументов для
каждого метода и т.д.). Также класс может обладать поведением, то есть поддерживать методы. А раз для
любого объекта существует шаблон, описывающий свойства и поведение этого объекта, то его можно
определить и для класса. Такой шаблон, задающий различные классы, называется метакласс.
Чтобы легче представить себе, что такое метакласс, рассмотрим пример некой бюрократической
организации. Будем считать, что все классы в такой системе - некоторые строгие инструкции, которые
описывают, что нужно сделать, чтобы породить новый объект (например, нанять нового служащего или
открыть новый отдел). Как и полагается классам, они описывают все свойства новых объектов (например,
зарплату и профессиональный уровень для сотрудников, площадь и имущество для отделов) и их
поведение (обязанности служащих и функции подразделений).
В свою очередь написание новой инструкции можно строго регламентировать. Скажем, необходимо
использовать специальный бланк, придерживаться правил оформления и заполнить все обязательные
поля (например, номер инструкции и фамилии ответственных работников) Такая "инструкция инструкций"
и будет представлять собой метакласс в ООП.
Итак, объекты порождаются от классов, а классы - от метакласса. Он, как правило, в системе есть только
один. Но существуют языки программирования, в которых можно создавать и использовать собственные
метаклассы, например язык Python. Например, функциональность метакласса может быть следующая:
при создании класса он будет просматривать список всех методов в классе и если имя метода имеет вид
set_XXX или get_XXX, то автоматически создать поле с именем XXX, если такого не существует.
Поскольку метакласс сам является классом, то нет никакого смысла в заведении "мета-мета-классов".
В языке Java также есть такое понятие. Это класс, который так и называется - Class (описывает классы) и
располагается в основной библиотеке java.lang. Виртуальная машина использует его по прямому
назначению. Когда загружается очередной .class-файл, содержащий описание нового класса, JVM
порождает объект класса Class, который будет хранить его структуру. Таким образом, Java использует
концепцию метакласса в самых практических целях. С помощью Class реализована поддержка
статических (static) полей и методов. Наконец, этот класс содержит ряд методов, полезных для
разработчиков. Они будут рассмотрены в следующих главах.
Программирование на Java
Rendered by www.RenderX.com
Стр. 18 из 24
Основы объектно-ориентированного программирования
1.6. Достоинства ООП
От любой методики разработки программного обеспечения мы ждем, что она поможет нам в решении
наших задач. Но одной из самых значительных проблем проектирования является сложность. Чем больше
и сложнее программная система, тем важнее становится разбить ее на небольшие, четко очерченные
части. Чтобы справиться со сложностью, необходимо абстрагироваться от мелких деталей. Для этой цели
классы представляют собой весьма удобный инструмент.
• Классы позволяют проводить конструирование из полезных компонент, обладающих простыми
инструментами, что дает возможность абстрагироваться от деталей реализации.
• Данные и операции над ними вместе образуют определенную сущность, и они не разносятся по всей
программе, как это нередко бывает в случае процедурного программирования, а описываются вместе.
Локализация кода и данных улучшает наглядность и удобство сопровождения программного обеспечения.
• Инкапсуляция позволяет привнести свойство модульности, что облегчает распараллеливание
выполнения задачи между несколькими исполнителями иобновление версий отдельных компонент.
ООП дает возможность создавать расширяемые системы. Это одно из самых значительных достоинств
ООП, и именно оно отличает данный подход от традиционных методов программирования.
Расширяемость означает, что существующую систему можно заставить работать с новыми компонентами,
причем без внесения в нее каких-либо изменений. Компоненты могут быть добавлены на этапе
исполнения программы.
Полиморфизм оказывается полезным преимущественно в следующих ситуациях.
• Обработка разнородных структур данных.
Программы могут работать, не различая вида объектов, что существенно упрощает код. Новые виды
могут быть добавлены в любой момент.
• Изменение поведения во время исполнения.
На этапе исполнения один объект может быть заменен другим, что позволяет легко без изменения кода
адаптировать алгоритм, в зависимости от того, какой используется объект.
• Реализация работы с наследниками.
Алгоритмы можно обобщить настолько, что они уже смогут работать более чем с одним видом объектов.
• Создание "каркаса" (framework).
Независимые от приложения части предметной области могут быть реализованы в виде набора
универсальных классов, или каркаса (framework), и в дальнейшем расширены за счет добавления частей,
специфичных для конкретного приложения.
Часто на практике многоразового использования программного обеспечения добиться не удается из-за
того, что существующие компоненты уже не отвечают новым требованиям. ООП помогает этого достичь
без нарушения работы уже имеющихся клиентов, что позволяет нам извлечь максимум из многоразового
использования компонент.
Программирование на Java
Rendered by www.RenderX.com
Недостатки ООП
Стр. 19 из 24
• Сокращается время на разработку, которое с выгодой может быть отдано другим задачам.
• Компоненты многоразового использования обычно содержат гораздо меньше ошибок, чем вновь
разработанные, ведь они уже не раз подвергались проверке.
• Когда некая компонента используется сразу несколькими клиентами, то улучшения, вносимые в ее код,
одновременно оказывают свое положительное влияние и на множество работающих с ней программ.
• Если программа опирается на стандартные компоненты, то ее структура и пользовательский интерфейс
становятся более унифицированными, что облегчает ее понимание и упрощает ее использование.
1.7. Недостатки ООП
Документирование классов - задача более трудная, чем это было в случае процедур и модулей.
Поскольку любой метод может быть переопределен, в документации должно говориться не только о том,
что делает данный метод, но также и о том, в каком контексте он вызывается. Ведь переопределенные
методы обычно вызываются не клиентом, а самим каркасом. Таким образом, программист должен знать,
какие условия выполняются, когда вызывается данный метод. Для абстрактных методов, которые пусты, в
документации должно даже говориться о том, для каких целей предполагается использовать
переопределяемый метод.
В сложных иерархиях классов поля и методы обычно наследуются с разных уровней. И не всегда легко
определить, какие поля и методы фактически относятся к данному классу. Для получения такой
информации нужны специальные инструменты вроде навигаторов классов. Если конкретный класс
расширяется, то каждый метод обычно сокращают перед передачей сообщения базовому классу.
Реализация операции, таким образом, рассредоточивается по нескольким классам, и чтобы понять, как
она работает, нам приходится внимательно просматривать весь код.
Методы, как правило, короче процедур, поскольку они осуществляют только одну операцию над данными.
Зато количество методов намного выше. Короткие методы обладают тем преимуществом, что в них легче
разбираться, неудобство же их связано с тем, что код для обработки сообщения иногда "размазан" по
многим маленьким методам.
Абстракцией данных не следует злоупотреблять. Чем больше данных скрыто в недрах класса, тем
сложнее его расширять. Отправной точкой здесь должно быть не то, что клиентам не разрешается знать о
тех или иных данных, а то, что клиентам для работы с классом этих данных знать не требуется.
Часто можно слышать, что ООП является неэффективным. Как же дело обстоит в действительности? Мы
должны четко проводить грань между неэффективностью на этапе выполнения, неэффективностью в
смысле распределения памяти и неэффективностью, связанной с излишней универсализацией.
1. Неэффективность на этапе выполнения. В языках типа Smalltalk сообщения интерпретируются во
время выполнения программы путем осуществления поиска их в одной или нескольких таблицах и за счет
выбора подходящего метода. Конечно, это медленный процесс. И даже при использовании наилучших
методов оптимизации Smalltalk-программы в десять раз медленнее оптимизированных С-программ.
Программирование на Java
Rendered by www.RenderX.com
Стр. 20 из 24
Основы объектно-ориентированного программирования
В гибридных языках типа Oberon-2, Object Pascal и С++ посылка сообщения приводит лишь к вызову
через указатель процедурной переменной. На некоторых машинах сообщения выполняются лишь на 10%
медленнее, чем обычные процедурные вызовы. И поскольку сообщения встречаются в программе гораздо
реже других операций, их воздействие на время выполнения влияния практически не оказывает.
Однако существует другой фактор, который влияет на время выполнения: это инкапсуляция данных.
Рекомендуется не предоставлять прямой доступ к полям класса, а выполнять каждую операцию над
данными через методы. Такая схема приводит к необходимости выполнения процедурного вызова при
каждом доступе к данным. Однако, когда инкапсуляция используется только там, где она необходима (т.е.
в случаях, где это становится преимуществом), то замедление вполне приемлемое.
2. Неэффективность в смысле распределения памяти. Динамическое связывание и проверка типа на
этапе выполнения требуют по ходу работы информации о типе объекта. Такая информация хранится в
дескрипторе типа, и он выделяется один на класс. Каждый объект имеет невидимый указатель на
дескриптор типа для своего класса. Таким образом, в объектно-ориентированных программах требуемая
дополнительная память выражается в одном указателе для объекта и в одном дескрипторе типа для
класса.
3. Излишняя универсальность. Неэффективность может также означать, что программа имеет ненужные
возможности. В библиотечном классе часто содержится больше методов, чем это реально необходимо. А
поскольку лишние методы не могут быть удалены, то они становятся мертвым грузом. Это не
воздействует на время выполнения, но влияет на возрастание размера кода.
Одно из возможных решений - строить базовый класс с минимальным числом методов, а затем уже
реализовывать различные расширения этого класса, которые позволят нарастить функциональность.
Другой подход - дать возможность компоновщику удалять лишние методы. Такие интеллектуальные
компоновщики уже доступны для различных языков и операционных систем.
Но нельзя утверждать, что ООП неэффективно. Если классы используются лишь там, где это
действительно необходимо, то потеря эффективности из-за повышенного расхода памяти и меньшей
производительности незначительна. Кроме того, часто более важной является надежность программного
обеспечения и небольшое время его написания, а не производительность.
1.8. Заключение
В этой главе Вы узнали об объектно-ориентированном подходе к разработке ПО, а также о том, что
послужило предпосылками к его появлению и сделало его популярным. Были рассмотрены ключевые
понятия ООП - объект и класс. Далее были описаны основные свойства объектной модели -
инкапсуляции, наследование полиморфизм. Основными видами отношений между классами являются
наследование, ассоциация, агрегация, метакласс. Также были описаны правила изображения классов и
связей между ними на языке UML.
Программирование на Java
Rendered by www.RenderX.com
Контрольные вопросы
Стр. 21 из 24
1.9. Контрольные вопросы
2-1. Почему объектно-ориентированное программирование пришло на смену процедурному
программированию?
а.) Как показала практика, традиционные методы процедурного программирования не способны
справиться ни с нарастающей сложностью программ и их разработки, ни с необходимостью повышения их
надежности. Во второй половине 80-х годов возникла настоятельная потребность в новой методологии
программирования, которая была бы способна решить эти проблемы. Такой методологией стало
объектно-ориентированное программирование (ООП).
2-2. Что такое объект? Приведите примеры.
а.) объектом называют понятие, абстракцию или любой предмет с четко очерченными границами,
имеющую смысл в контексте рассматриваемой прикладной проблемы. Введение объектов преследует две
цели:
• понимание прикладной задачи (проблемы);
• введение основы для реализации на компьютере.
Примеры объектов: форточка, Банк "Империал", Петр Сидоров, дело № 7461, сберкнижка и т.д.
2-3. Что из перечисленного является классами, а что объектами:
1. яблоко;
2. Иван Сидорович Петров;
3. легковой автомобиль;
4. Страховое свидетельство №113-043-429-18.
а.) Яблоко и легковой автомобиль являются классами, а Иван Сидорович Петров и страховое
свидетельство №113-043-429-18 - объектами.
Классом всегда является более общее понятие, а объектом - более конкретное. Например, для страхового
свидетельства №113-043-429-18 классом будет являться просто страховое свидетельство, а примером
объекта для класса «яблоко» может быть «большое красное яблоко».
Программирование на Java
Rendered by www.RenderX.com
Стр. 22 из 24
Основы объектно-ориентированного программирования
2-4. Найдите ошибку на приведенной диаграмме:
а.) На диаграмме неверно изображены стрелки обозначающие наследование. Класс «Человек» является
более общим по отношению к классам «Студент» и «Лектор» следовательно, он является предком этих
классов. Направление стрелок обозначающих наследование должно быть от предка к наследнику.
2-5. Перечислите основные состояния для кофейного автомата. а.) Примеры состояний кофейного
автомата:
1. ожидание монеты;
2. ожидание выбора напитка покупателем;
3. наливает напиток в стакан;
4. ждет, пока покупатель заберет наполненный стакан.
2-6. Что используется для описания поведения объекта? Варианты ответов:
1. поля;
2. методы;
3. наследование.
а.) Ответ: для описания поведения объектов какого-либо класса используются методы.
2-7. Зачем нужен полиморфизм?
а.) Полиморфизм используется для написания общего кода, который будет одинаково работать с разными
типами данных (объектами разных классов), при условии что классы, от которых созданы эти объекты,
имеют общего предка.
2-8. Какое отношение существует между человеком и каким-либо внутренним органом этого человека:
ассоциация или агрегация? Объясните почему.
Программирование на Java
Rendered by www.RenderX.com
Контрольные вопросы
Стр. 23 из 24
а.) Ответ: агрегация. Человеческий организм состоит из органов. Обычно, если к классам применимо
выражение «состоит из» или «содержит», то используется агрегация, а не ассоциация.
2-9. Даны объекты: моторная лодка, вездеход, амфибия. Какие классы Вы бы спроектировали для
моделирования этих объектов? Постройте дерево наследования этих классов.
2-10. Даны объекты:
1. Книга «иауа2: руководство разработчика»
2. Страница № 342 из книги «иауа2: руководство разработчика»
3. Книга «Война и Мир»
4. Вася (покупатель)
Нарисуйте диаграмму классов для данных объектов.
2-11. Даны классы «Здание» и «Гараж», наследования между ними нет. Класс «Здание» обладает такими
свойствами, как адрес, количество этажей и т.п. Класс «Гараж» имеет свойства «вместимость»
(максимальное количество автомобилей, которые могут быть размещены в нем), «размер» (максимально
допустимая длина машины). Необходимо, используя существующие классы, спроектировать 2 новых
класса:
1. Многоэтажный гараж (целое здание, предназначенное для парковки автомобилей)
2. Коттедж с гаражом (жилой дом с пристроенным гаражом, или гаражом в
а.) Ответ:
a.)
цокольном этаже)
Программирование на Java
Rendered by www.RenderX.com
Стр. 24 из 24
Основы объектно-ориентированного программирования
Нарисуйте диаграмму классов и обозначьте на ней отношения между классами. а.) Ответы:
2-12. Спроектируйте класс «Кофейный автомат». Напишите, какие свойства и методы вы бы включили в
этот класс.
а.) Один из вариантов класса для кофейного автомата:
2-13. Даны классы «Кофейный автомат», «Монета», «Бумажная купюра». Как можно улучшить модель,
чтобы не писать различный код в классе «кофейный автомат» для работы с монетами и с бумажными
деньгами, при условии, что монеты и бумажные купюры должны обрабатываться одинаковым образом.
а.) Ответ: создать новый класс «Деньги», наследниками которого сделать классы «Монета» и «Бумажная
купюра». В классе «Кофейный автомат» написать код, который будет использовать класс «Деньги».
Благодаря полиморфизму написанный код сможет также работать с экземплярами классов «Монета» и
«Бумажная купюра».
2.
Программирование на Java
Rendered by www.RenderX.com
Контрольные вопросы
Стр. 25 из 24
2-14. Что из перечисленного является в классе «Лифт» деталями реализации, а что -внешним
интерфейсом:
• кнопки управления;
• разводка проводов;
• реакция на нажатие какой-либо кнопки;
• количество людей в лифте;
• марка металла, из которого изготовлен трос.
а.) Ответ:
Внешний интерфейс:
• кнопки управления;
• количество людей в лифте; Детали реализации:
• разводка проводов;
• реакция на нажатие какой-либо кнопки;
• марка металла, из которого изготовлен трос.
Программирование на Java
Rendered by www.RenderX.com
Программирование на Java ()
Программирование на Java
Rendered by www.RenderX.com