Вы находитесь на странице: 1из 25

Практика программирования

19
➔ Объектно-ориентированное
программирование
➔ Понятие паттерна ООП
➔ Введение в диаграммы классов UML
➔ Private implementation

Кувшинов Д.Р.
КМиММ УрФУ
Екатеринбург 2012
Истоки ООП
● Имитационное моделирование
– Язык должен предоставлять удобные
средства описания моделируемых объектов
реального мира
– Объекты могут быть «классифицированы»
соответственно родо-видовым отношениям,
разбиты на множества – классы
● Развитие модульного программирования на
основе структурного программирования
– Отделение интерфейса от реализации
– Сокрытие деталей реализации модуля
(инкапсуляция)
Принципы ООП
● Абстракция
– Класс объектов представляет собой
формальное описание модели некоторых
реальных объектов либо отвечает
некоторому понятию («существительное»)
предметной области
– Выделяя классы, следует выбирать
подходящий уровень абстракции, оставляя
минимум того, что требуется для решения
задачи, но и не уходя в слишком
пространные обобщения
Принципы ООП
● Абстракция
– Объектно-ориентированные компоненты
абстрагируются от данных, предоставляя
интерфейсы в виде наборов функций.
– Конкретика работы функций определяется
каждым объектом независимо от других в
соответствии с его реальным внутренним
устройством и текущим состоянием, однако
пользователь объекта обычно может
позволить себе не знать детали.
Принципы ООП
● Уникальность объекта (C++)
– Объект существует как отдельная сущность,
имеет состояние, хранимое в памяти
компьютера (таким образом, имеет
уникальный адрес в памяти)
– Класс можно понимать как «чертёж»,
определяющий как создать объект
(конструкторы), что собой представляет
состояние объекта (его свойства), какие
действия можно выполнять с объектом (в
частности, как его уничтожать –
деструктор)
– Класс – тип, его объект – значение этого типа
Принципы ООП
● Инкапсуляция
– Состояние объекта, выраженное как набор
значений (аналогично полям структуры),
следует по мере возможности скрывать от
доступа извне (private-секция)
– Изменение состояния производится в
соответствии с ролью объекта путём
вызова его функций-членов (методов)
– Таким образом, мы предоставляем
пользователям объектов и классов
интерфейс, но оставляем за собой право
распоряжаться реализацией (выполняя
«контракт», заданный интерфейсом)
Принципы ООП
● Наследование
– Новые классы могут «уточнять» ранее
введённые классы, выделяя некоторые
важные возможные подмножества
объектов
– В C++ наследующий класс фактически
является надстройкой над классом-базой,
объект класса-наследника неявно включает
в себя объект класса-базы
– protected-секция позволяет предоставить
наследникам дополнительный интерфейс
(возможно, более низкоуровневый),
protected-члены класса будут доступны
только его наследникам
Принципы ООП
● Полиморфизм
– Объекты класса-наследника могут
использоваться там, где могут
использоваться объекты класса-базы
– В C++ ключевое слово virtual позволяет
указать функции-члены, вызов которых
(через указатель/ссылку на объект) будет
разрешаться во время исполнения, а не
компиляции, таким образом, выполняя код,
соответствующий реальному классу
объекта, а не типу указателя/ссылки (в
месте вызова), известному компилятору
– Нередко только virtual функции-члены
называют собственно «методами»
Принципы ООП
● Абстрактный класс
– Если класс представляет собой некоторое
достаточно общее понятие и изначально
предназначен быть классом-базой для
классов, которые будут уже отвечать
реальным объектам, то такой класс называют
«абстрактным»
– В C++ абстрактным классом считается класс
хотя бы с одной чисто виртуальной функцией
(вроде virtual void foo() = 0;), класс-наследник
должен дать определения для
унаследованных чисто виртуальных функций
– До тех пор, пока не даны определения для всех
унаследованных чисто виртуальных функций,
объекты этого класса создавать будет нельзя
Принципы ООП
● Интерфейс
– Класс, не содержащий свойств и функций-
членов, не являющихся чисто
виртуальными, часто называют
«интерфейсом»,
так как он содержит лишь интерфейс,
реализуемый уже в классах-наследниках
Отношения между классами
● Наследование (отношение «is-a»)
– класс A является наследником класса B
● Агрегация (отношение «has-a»)
– объект класса A содержит объект(ы) класса B
● Композиция (усиленный вариант агрегации)
– объект класса A состоит из объектов класса B
● Использование (направленная ассоциация)
– методы класса A используют объекты класса B
● Ассоциация (любой другой вид отношения)
– классы A и B «знают» друг о друге
Методы – терминология
● Если поле (свойство) скрыто, метод, позволяющий
получить его значение, называется геттером
● Аналогично, метод, позволяющий установить
новое значение свойства, называют сеттером
● В целом, методы, не изменяющие состояние
объекта называют аксессорами (accessor) или
селекторами, например, в C++:
– virtual int getId() const = 0;
● Изменяющие состояние – мутаторами (mutator)
или модификаторами, например, в C++:
– virtual void nextStep (double timeStamp) = 0;
Геттеры и сеттеры
● В тривиальном случае пара «геттер-сеттер» может
казаться (или действительно быть) избыточной:
class Person {
string name;
public:
const string& getName() const
{ return name; }
void setName (const string &value)
{ name = value; }
Геттеры и сеттеры
● Однако благодаря инкапсуляции можно расширить
поведение геттеров/сеттеров, например, сеттер
может проверять данные на корректность:
class Person {
string name;
public:
const string& getName() const
{ return name; }
void setName (const string &value) {
if (value.empty()) throw exception ("empty name");
name = value;
}
Геттеры и сеттеры
● Более того, свойство может быть реализовано
неявно (не храниться в виде значения поля объекта).
class Person {
DataBaseIdentifier id;
public:
const string& getName() const
{ return db.getField("Persons", "Name", id); }
void setName (const string &value) {
if (value.empty()) throw exception ("empty name");
db.setField("Persons", "Name", id, value);
}
Паттерны объектно-ориентированного
проектирования
● Под «паттерном ООП» подразумевается некоторый
характерный способ организации структуры классов /
взаимодействия классов
● Паттерны подсказывают разумный подход к решению
типичных задач проектирования и имеют
общепринятые названия (задают терминологию)
● Характерный набор паттернов зависит от конкретного
языка программирования: если определённый
механизм поддержан непосредственно на уровне
языка, то он не считается «паттерном»
– например, в C нет наследования и виртуальных
функций, их имитация может считаться паттерном, в
то время как в C++ они есть и паттернами уже не
считаются
Паттерны ООП
● Для описания структуры того или иного
паттерна удобно использовать диаграммы
классов UML (unified modelling language)
● Далее показан способ изображения класса в
UML и виды отношений между классами
● Для краткости в UML-диаграмме некоторые
детали могут быть опущены (например, в
последней функции string принимается по
ссылке, что не отражено на диаграмме)
На C++
class MyClass {
private:
int myPrivate;
void onlySelfCanDo();
protected:
bool myProtected;
bool onlyChildCanDo();
public:
string myPublic;
void doIt (const string &what);
};
UML диаграмма
класса MyClass
Отношения между классами в UML
● Наследование

(public-наследование в C++)

● Агрегация

● Композиция

● Использование

● Ассоциация
Интерфейсы и абстрактные
классы
● Названия абстрактных классов (и «интерфейсов»
в C++) принято давать курсивом
● Аналогично, курсивом набираются абстрактные
методы (чисто виртуальные функции в C++)
● Наследование интерфейса (его реализация)
изображается похоже на наследование класса
(его расширение), но используется не сплошная,
а штриховая линия
Интерфейсы и абстрактные
классы
Private implementation (pimpl)
● Для увеличения степени инкапсуляции и
свободы вносить изменения в реализацию
в C++ используется паттерн pimpl
● Реализация выносится в отдельный класс,
содержимое которого не публикуется в .h
файле
● В .h файле публикуется «прокси»-класс,
управляющий объектом реализации через
указатель и содержащий внешний интерфейс к
этому объекту
● Собственно реализация «спрятана» в
отдельный .cpp файл
Private implementation (pimpl)
Пример: класс «Окно» (графического
интерфейса)
Private implementation (pimpl)
● Window.h файл, реализация – в Window.cpp файле:
class Window {
class WindowImpl;
WindowImpl *wnd;
public:
Window();
Window (const Window&);
explicit Window (const Rectangle&, const string&);
virtual ~Window();
void move (const Rectangle&);
void show (bool);
void setTitle (const string&);
};

Вам также может понравиться