close

Вход

Забыли?

вход по аккаунту

?

1371.Основы объектного проектирования и программирования учеб.-метод. пособие для лаб

код для вставкиСкачать
Министерство образования и науки Российской Федерации
Сибирский федеральный университет
ОСНОВЫ ОБЪЕКТНОГО ПРОЕКТИРОВАНИЯ
И ПРОГРАММИРОВАНИЯ
Учебно-методическое пособие для лабораторных работ
Электронное издание
Красноярск
СФУ
2012
УДК 004.4(07)
ББК 22.18я73
О-753
Составитель: Ю.Ю. Якунин
О-753 Основы объектного проектирования и программирования: учебнометодическое пособие для лабораторных работ [Электронный ресурс] /
сост. Ю.Ю. Якунин. – Электрон. дан. – Красноярск: Сиб. федер. ун-т,
2012. – Систем. требования: PC не ниже класса Pentium I; 128 Mb RAM;
Windows 98/XP/7; Adobe Reader V8.0 и выше. – Загл. с экрана.
Учебно-методическое пособие содержит курс лабораторных работ с методическими указаниями по их выполнению, разъяснениями теоретического материала
и примерами по дисциплине «Основы объектного проектирования и программирования».
Предназначено для студентов направления 220100.62 – «Системный анализ и
управление».
УДК 004.4(07)
ББК 22.18я73
© Сибирский
федеральный
университет, 2012
Учебное издание
Подготовлено к публикации редакционно-издательским
отделом БИК СФУ
Подписано в свет 16.07.2012 г. Заказ 8390.
Тиражируется на машиночитаемых носителях.
Редакционно-издательский отдел
Библиотечно-издательского комплекса
Сибирского федерального университета
660041, г. Красноярск, пр. Свободный, 79
Тел/факс (391)206-21-49. E-mail rio@sfu-kras.ru
http://rio.sfu-kras.ru
2
ОГЛАВЛЕНИЕ
ЛАБОРАТОРНАЯ РАБОТА №1. КЛАССЫ И ОБЪЕКТЫ ............................. 4 ЦЕЛЬ И ЗАДАНИЕ ........................................................................................................ 4 КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ ........................................................................... 4 ПОРЯДОК ВЫПОЛНЕНИЯ РАБОТЫ ............................................................................... 9 МЕТОДИЧЕСКИЕ УКАЗАНИЯ ....................................................................................... 9 ЛАБОРАТОРНАЯ РАБОТА №2. НАСЛЕДОВАНИЕ И ВИРТУАЛЬНЫЕ
МЕТОДЫ .................................................................................................................. 11 ЦЕЛЬ И ЗАДАНИЕ ...................................................................................................... 11 ЗАДАНИЕ .................................................................................................................. 11 КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ ..................................................................... 11 ВАРИАНТЫ ЗАДАНИЙ ............................................................................................... 17 ЛАБОРАТОРНАЯ РАБОТА №3. МОДЕЛЬ ВАРИАНТОВ
ИСПОЛЬЗОВАНИЯ ............................................................................................... 17 ЦЕЛЬ И ЗАДАНИЕ ...................................................................................................... 17 КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ ..................................................................... 18 СПЕЦИФИКАЦИЯ ВАРИАНТОВ ИСПОЛЬЗОВАНИЯ ..................................................... 19 ПРИМЕР СПЕЦИФИКАЦИИ ВАРИАНТА ИСПОЛЬЗОВАНИЯ ......................................... 22 КОНТРОЛЬНЫЕ ВОПРОСЫ ......................................................................................... 23 ЛАБОРАТОРНАЯ РАБОТА №4. ШАБЛОНЫ РАСПРЕДЕЛЕНИЯ
ОБЯЗАННОСТЕЙ ................................................................................................... 23 ЦЕЛЬ И ЗАДАНИЕ ...................................................................................................... 23 МЕТОДИЧЕСКИЕ УКАЗАНИЯ ..................................................................................... 23 ЛАБОРАТОРНАЯ РАБОТА №5. ПОРОЖДАЮЩИЕ ШАБЛОНЫ ............ 30 ЦЕЛЬ И ЗАДАНИЕ ...................................................................................................... 30 МЕТОДИЧЕСКИЕ УКАЗАНИЯ ..................................................................................... 30 ЛАБОРАТОРНАЯ РАБОТА №6. ШАБЛОНЫ ПОВЕДЕНИЯ ...................... 34 ЦЕЛЬ И ЗАДАНИЕ ...................................................................................................... 34 МЕТОДИЧЕСКИЕ УКАЗАНИЯ ..................................................................................... 34 БИБЛИОГРАФИЧЕСКИЙ СПИСОК ................................................................ 39 3
ЛАБОРАТОРНАЯ РАБОТА №1. КЛАССЫ И ОБЪЕКТЫ
ЦЕЛЬ И ЗАДАНИЕ
Цель работы
Приобрести навыки создания классов, объектов и отношений между ними
в объектно-ориентированных программных системах.
Задание
Разработать программу путём создания классов и отношений между ними, в которой создаются и удаляются объекты (экземпляры созданных классов).
Выполнить исследование вызовов конструкторов и деструкторов.
КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ
Классы и объекты
Объект – это абстракция, сущность, обладающая индивидуальностью и
имеющая смысл в рамках приложения. Объект является экземпляром класса.
Класс описывает группу объектов с одинаковыми свойствами, одинаковым поведением, типами отношений и семантикой. Каждый
экземпляр класса имеет собственные значения свойств.
В объектно-ориентированных языках программирования класс можно определить с помощью конструкции
тип_класса имя_класса {список_членов_класса} (рис. 1.1),
Рис. 1.1. Класс
где: тип_класса – одно из служебных; имя_класса – идентификатор; список_членов_класса – определения и описания
свойств (структура) и методов (поведение) класса. Все члены класса защищены
одним из трёх уровней, которые определяют к ним доступ из разных точек программы. Уровни защищённости элементов класса − public, private, protected.
Общедоступные, открытые (public) члены доступны в любой части программы,
они могут использоваться любой функцией как внутри данного класса, так и
вне его. Собственные, закрытые (private) члены локализованы в классе и не
доступны извне. Защищенные (protected) члены доступны
внутри класса и в производных классах (наследниках).
Рассмотрим пример описания класса TComplex (рис.
1.2), предназначенного для представления (описания) комплексного числа. Класс TComplex имеет два закрытых свойства: fImInt – мнимая часть комплексного числа; fDInt – действительная часть комплексного числа, и четыре открытых метода:
setIm() – задание значения свойства fImInt; getIm() – получение
Рис. 1.2. Класс значения свойства fImInt; аналогично для свойства fDInt – меTComplex
4
тоды setD() и getD(). Ниже представлен код класса TComplex для Delphi.
unit uComplex;
interface
type
TСomplex = class
private
fIm, fD: Integer;
function getIm : Integer;
procedure setIm (val : Integer);
function getD : Integer;
procedure setD (val : Integer);
public
property Im : Integer read getIm write setIm;
property D : Integer read getD write setD;
end;
implementation
function TComplex.getIm;
begin
result := fIm;
end;
procedure TComplex.setIm(val: Integer);
begin
fIm := val;
end;
function TComplex.getD;
begin
result := fD;
end;
procedure TComplex.setD(val: Integer);
begin
fD := val;
end;
end.
Важными членами класса являются методы, которые вызываются при
создании объекта (конструктор) и удалении объекта (деструктор).
Конструктор
Конструктор выделяет память для объекта и инициализирует свойства
класса. Конструктор имеет ряд особенностей:
− для конструктора не определяется тип возвращаемого значения;
− конструкторы не наследуются;
5
− конструкторы не могут быть описаны с ключевыми словами virtual,
static, const, mutuable, valatile;
− конструктор всегда существует для любого класса, причем, если он не
определен явно, он создается автоматически. Если конструктор описан явно, то
конструктор по умолчанию не создается.
Для явного вызова конструктора используются две формы:
имя_класса имя_объекта (фактические_параметры);
имя_класса (фактические_параметры).
Первая форма допускается только при не пустом списке фактических параметров. Она предусматривает вызов конструктора при определении нового
объекта данного класса: TComplex cmplx (1.9, 2.3).
Вторая форма вызова приводит к созданию объекта без имени: TComplex
cmplx = TComplex (1.9, 2.3);
Существуют два способа инициализации данных объекта с помощью
конструктора. Ранее мы рассматривали первый способ, а именно, передача значений параметров в тело конструктора. Второй способ предусматривает применение списка инициализаторов данного класса. Этот список помещается между
списком параметров и телом конструктора. Каждый инициализатор списка относится к конкретному компоненту и имеет вид: имя_данного (выражение).
Ниже приведены примеры конструкторов на языке С++.
class CLASS_A {
int i; float e; char c;
public:
CLASS_A(int ii, float ee, char cc) : i(8), e(i*ee + ii),
с(сс) {}
. . .
};
Класс “символьная строка”
#include <string.h>
#include <iostream.h>
class string
{
char *ch; // указатель на текстовую строку
int len; // длина текстовой строки
public:
// конструкторы
// создает объект – пустая строка
string(int N = 80): len(0){ch = new char[N+1]; ch[0] = ‘\0’;}
// создает объект по заданной строке
string(const char *arch){len = strlen(arch);
ch = new char[len+1];
6
strcpy(ch,arch);}
// компоненты-функции
// возвращает ссылку на длину строки
int& len_str(void){return len;}
// возвращает указатель на строку
char *str(void){return ch;}
. . .};
Здесь у класса string два конструктора – перегружаемые функции. По
умолчанию создается также конструктор копирования вида T::T(const T&), где
Т – имя класса. Конструктор копирования вызывается всякий раз, когда выполняется копирование объектов, принадлежащих классу. В частности он вызывается:
− когда объект передается функции по значению;
− при построении временного объекта как возвращаемого значения
функции;
− при использовании объекта для инициализации другого объекта.
Если класс не содержит явным образом определенного конструктора копирования, то при возникновении одной из этих трех ситуаций производится
побитовое копирование объекта. Побитовое копирование не во всех случаях
является адекватным. Именно для таких случаев и необходимо определить собственный конструктор копирования. Например, в классе string:
string(const string& st)
{len=strlen(st.len);
ch=new char[len+1];
strcpy(ch,st.ch);}
Можно создавать массив объектов, однако при этом соответствующий
класс должен иметь конструктор по умолчанию (без параметров). Массив объектов может инициализироваться либо автоматически конструктором по умолчанию, либо явным присваиванием значений каждому элементу массива.
class demo{
int x;
public:
demo(){x=0;}
demo(int i){x=i;}
};
void main(){
class demo a[20]; //вызов конструктора без параметров(по
умолчанию)
class demo b[2]={demo(10),demo(100)};//явное присваивание
7
Деструктор
Динамическое выделение памяти для объекта создает необходимость освобождения этой памяти при удалении объекта. Например, если объект формируется как локальный внутри блока, то целесообразно, чтобы при выходе из
блока, когда уже объект перестает существовать, выделенная для него память
была возвращена. Желательно, чтобы освобождение памяти происходило автоматически. Такую возможность обеспечивает специальный компонент класса –
деструктор. Его формат: ~имя_класса() {операторы_тела_деструктора}. Имя
деструктора совпадает с именем его класса, но предваряется символом “~”
(тильда). Деструктор не имеет параметров и возвращаемого значения. Вызов
деструктора выполняется не явно (автоматически), как только объект класса
уничтожается. Например, при выходе за область определения или при вызове
оператора delete для указателя на объект.
string *p=new string “строка”);
delete p;
Если в классе деструктор не определен явно, то компилятор генерирует
деструктор по умолчанию, который просто освобождает память, занятую данными объекта. В тех случаях, когда требуется выполнить освобождение и других объектов памяти, например область, на которую указывает ch в объекте
string, необходимо определить деструктор явно:
~string(){delete []ch;}
Основные ассоциации между классами
Связь – это физическое или концептуальное соединение между объектами. С математической точки зрения связь является кортежем, списком (множеством) объектов.
Ассоциация – это описание группы связей,
обладающих общей структурой и общей семантикой. Каждая ассоциация имеет один или два полюса, у которых соответственно есть роль и мощность. Роль показывает природу взаимосвязи объекта(в) одного класса по отношению к объекту(ам)
другого класса. Мощность показывает со сколькими объектами некоторого класса, связан объект
данного класса.
На рисунке 1.3 приведён пример однонаправленной ассоциации от класса Goods к классу
GoodsType с ролью type и мощностью 1, и самоассоциация класса GoodsType с наименованием classification и полюсом с ролью parentType и мощно- Рис. 1.3. Ассоциации классов
стью «0..1».
8
Однонаправленная ассоциация с мощностью n устанавливается между классами, когда
требуется объект одного класса связать с неРис. 1.4. Ассоциация –
сколькими объектами другого класса. Объект
коллекция
класса, из которого исходит такая ассоциация, содержит в себе свойство-коллекцию, способное содержать в себе объекты класса, принимающего ассоциацию (рис. 1.4).
ПОРЯДОК ВЫПОЛНЕНИЯ РАБОТЫ
1. Определить пользовательский класс в соответствии с вариантом задания.
2. Определить в классе конструкторы: без параметров, с параметрами, копирования.
3. Определить в классе деструктор.
4. Определить в классе методы для получения (чтения) и задания (определения) значений свойств.
5. Написать демонстрационную программу, в которой создаются и удаляются
объекты пользовательского класса и каждый вызов конструктора и деструктора
сопровождается выдачей соответствующего сообщения (какой объект какой
конструктор или деструктор вызывался).
6. Создать два дополнительных класса и установить с одним из них однонаправленную ассоциацию с мощностью «1», а с другим – однонаправленную ассоциацию с мощностью «n».
7. В демонстрационной программе реализовать возможность создания объектов дополнительных классов и связать их с объектом основного класса.
МЕТОДИЧЕСКИЕ УКАЗАНИЯ
Пример определения класса.
const int LNAME=25;
class STUDENT{
char name[LNAME]; // имя
int age; // возраст
float grade; // рейтинг
public:
STUDENT(); // конструктор без параметров
STUDENT(char*,int,float); // конструктор с параметрами
STUDENT(const STUDENT&); // конструктор копирования
~STUDENT();
char * GetName() ;
int GetAge() const;
float GetGrade() const;
9
void
void
void
void
void
SetName(char*);
SetAge(int);
SetGrade(float);
Set(char*,int,float);
Show(); };
Более профессионально определение поля name типа указатель: char*
name. Однако в этом случае реализация методов усложняется.
Пример реализации конструктора с выдачей сообщения.
STUDENT::STUDENT(char*NAME,int AGE,float GRADE)
{
strcpy(name,NAME); age=AGE; grade=GRADE;
cout<< \nКонструктор с параметрами вызван для объекта
<<this<<endl;
}
Следует предусмотреть в программе все возможные способы вызова конструктора копирования. Вспомним, что конструктор копирования вызывается:
а) при использовании объекта для инициализации другого объекта, напсриемер:
STUDENT a(“Иванов”,19,50), b=a;
б) когда объект передается функции по значению, например:
void View(STUDENT a){a.Show;}
в) при построении временного объекта как возвращаемого значения
функции, например:
STUDENT NoName(STUDENT & student)
{STUDENT temp(student);
temp.SetName(“NoName”);
return temp;}
STUDENT c=NoName(a);
В программе необходимо предусмотреть размещение объектов, как в статической, так и в динамической памяти, а также создание массивов объектов:
а) массив студентов размещается в статической памяти
STUDENT gruppa[3];
gruppa[0].Set(“Иванов”,19,50);
и т.д., или
STUDENT gruppa[3]={STUDENT(“Иванов”,19,50),
STUDENT(“Петрова”,18,25.5),
STUDENT(“Сидоров”,18,45.5)};
б) массив студентов размещается в динамической памяти
STUDENT *p;
p=new STUDENT [3];
p-> Set(“Иванов”,19,50);
10
и т.д.
Программа использует три файла: заголовочный h-файл с определением
класса; cpp-файл с реализацией класса; сpp-файл демонстрационной программы.
ЛАБОРАТОРНАЯ РАБОТА №2.
НАСЛЕДОВАНИЕ И ВИРТУАЛЬНЫЕ МЕТОДЫ
ЦЕЛЬ И ЗАДАНИЕ
Получить практические навыки создания иерархии классов и использования принципа полиморфизма посредствам перегрузки методов.
ЗАДАНИЕ
Написать программу, в которой создается иерархия классов. Включить
полиморфные объекты в связанный список. Реализовать использование виртуальных методов.
КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ
Статические члены класса
Статические члены должны быть определены в классе ключевым словом
static. Статические члены классов не дублируются при создании объектов, т.е.
каждый статический член существует в единственном экземпляре. Доступ к
статическому члену возможен только после его инициализации. Для инициализации статического свойства используется конструкция тип имя_класса : :
имя_свойства инициализатор, например, int complex : : count = 0. Это предложение должно быть размещено в глобальной области после определения класса. Только при инициализации статическое свойство класса получает память и
становится доступным. Обращаться к статическому свойству класса можно
обычным образом через имя объекта имя_объекта.имя_свойства.
Но к статическим членам можно обращаться и тогда, когда объект класса
еще не существует. Доступ к статическим членам возможен не только через
имя объекта, но и через имя класса − имя_класса : : имя_члена. Однако так
можно обращаться только к public членам.
Для обращения к private статическому свойству извне можно с помощью
статических методов. Эти методы можно вызвать через имя класса −
имя_класса : : имя_статическго_метода. Пример.
#include <iostream.h>
class TPoint {
double x,y;
static int N; // статическое свойство : количество точек
11
public:
TPoint(double x1 = 0.0,double y1 = 0.0){N++; x = x1; y = y1;}
static int& count(){return N;} // статический метод
};
int TPoint : : N = 0; //инициализация статического свойства
void main(void){
TPoint A(1.0,2.0);
TPoint B(4.0,5.0);
TPoint C(7.0,8.0);
cout<< \nОпределены ”<<TPoint : : count()<<“точки”; }
Указатель this
Когда метод класса вызывается для обработки данных конкретного объекта, этому методу автоматически и неявно передается указатель на тот объект,
для которого метод вызван. Этот указатель имеет имя this и неявно определен в
каждой функции класса следующим образом: имя_класса *const this = адрес_объекта.
Указатель this является дополнительным скрытым параметром каждого
метода объекта. При входе в тело принадлежащего классу метода this инициализируется значением адреса того объекта, для которого вызван метод. В результате этого объект становится доступным внутри этого метода.
В большинстве случаев использование this является неявным. В частности, каждое обращение к методу объекта неявно используется this для доступа к
члену соответствующего объекта.
Наследование
Наследование − это механизм получения нового класса на основе уже
существующего. Существующий класс может быть дополнен или изменен для
создания нового класса. Существующие классы называются базовыми, а новые
– производными. Производный класс наследует описание базового класса; затем он может быть изменен добавлением новых членов, изменением существующих членов и изменением прав доступа. С помощью наследования может
быть создана иерархия классов, которые совместно используют код и интерфейсы.
Наследуемые члены не перемещаются в производный класс, а остаются в
базовых классах. В иерархии производный объект наследует разрешенные для
наследования члены всех базовых классов (public, protected).
Допускается множественное наследование – возможность для некоторого
класса наследовать члены нескольких никак не связанных между собой базовых
классов.
12
Синтаксис определения производного класса:
class имя_класса : список_базовых_классов
{список_членов_класса};
В производном классе унаследованные компоненты получают статус доступа private, если новый класс определен с помощью ключевого слова class, и
статус public, если с помощью struct.
Явно изменить статус доступа по умолчанию при наследовании можно с
помощью атрибутов доступа – private, protected и public, которые указываются
непосредственно перед именами базовых классов.
Конструкторы и деструкторы производных классов
Поскольку конструкторы не наследуются, при создании производного
класса наследуемые им члены должны инициализироваться конструктором базового класса. Конструктор базового класса вызывается автоматически и выполняется до конструктора производного класса. Параметры конструктора базового класса указываются в определении конструктора производного класса.
Таким образом происходит передача аргументов от конструктора производного
класса конструктору базового класса. Например:
class Basis {
int a,b;
public:
Basis(int x,int y){a=x;b=y;}
};
class Inherit:public Basis {
int sum;
public:
Inherit(int x,int y, int s):Basis(x,y){sum=s;}
};
Объекты класса конструируются снизу вверх: сначала базовый, потом
члены-объекты (если они имеются), а потом сам производный класс. Таким образом, объект производного класса содержит в качестве подобъекта объект базового класса.
Удаляются объекты в обратном порядке: сначала производный, потом его
члены-объекты, а потом базовый объект. Таким образом, порядок удаления
объекта противоположен по отношению к порядку его конструирования.
Виртуальные методы
Здесь и далее функцией будем называть метод класса. К механизму виртуальных функций обращаются в тех случаях, когда в каждом производном
классе требуется свой вариант реализации функции. Классы, включающие такие функции, называются полиморфными и играют особую роль в ООП.
13
Виртуальные функции предоставляют механизм позднего (отложенного)
или динамического связывания. Любая функция объекта базового класса может
быть сделана виртуальной, для чего используется ключевое слово virtual.
class base {
public:
virtual void print(){cout<<“\nbase”;}
. . .
};
class dir : public base {
public:
void print(){cout<<“\ndir”;}
};
void main() {
base B,*bp = &B;
dir D,*dp = &D;
base *p = &D;
bp –>print(); // base
dp –>print(); // dir
p –>print(); // dir
}
Таким образом, интерпретация каждого вызова виртуальной функции через указатель на базовый класс зависит от значения этого указателя, т.е. от типа
объекта, для которого выполняется вызов. Выбор того, какую виртуальную
функцию вызвать, будет зависеть от типа объекта, на который фактически (в
момент выполнения программы) направлен указатель, а не от типа указателя.
Виртуальными могут быть только нестатические функции – функции
объектов. Виртуальность наследуется. После того как функция определена как
виртуальная, её повторное определение в производном классе (с тем же самым
прототипом) создает в этом классе новую виртуальную функцию, причем спецификатор virtual может не использоваться.
Конструкторы не могут быть виртуальными, в отличие от деструкторов.
Практически каждый класс, имеющий виртуальную функцию, должен иметь
виртуальный деструктор.
Абстрактные классы
Абстрактным называется класс, в котором есть хотя бы одна чистая (пустая) виртуальная функция. Чистой виртуальной функцией называется функция
объекта, которая имеет следующее определение: virtual тип имя_функции (список_аргументов) = 0.
Чистая виртуальная функция ничего не делает и недоступна для вызовов.
Ее назначение – служить основой для подменяющих ее функций в производных
14
классах. Абстрактный класс может использоваться только в качестве базового
для производных классов.
Механизм абстрактных классов разработан для представления общих понятий, которые в дальнейшем предполагается конкретизировать. При этом построение иерархии классов выполняется по следующей схеме. Во главе иерархии стоит абстрактный базовый класс. Он используется для наследования интерфейса. Производные классы будут конкретизировать и реализовать этот интерфейс. В абстрактном классе объявлены чистые виртуальные функции, которые по сути есть абстрактные методы.
class Base{
public:
Base(); // конструктор по умолчанию
Base(const Base&); // конструктор копирования
virtual ~Base(); // виртуальный деструктор
virtual void Show()=0; // чистая виртуальная функция
// другие чистые виртуальные функции
protected: // защищенные члены класса
private:
// часто остается пустым, иначе будет мешать будущим разработкам
};
class Derived: virtual public Base{
public:
Derived(); // конструктор по умолчанию
Derived(const Derived&); // конструктор копирования
Derived(параметры); // конструктор с параметрами
virtual ~Derived(); // виртуальный деструктор
void Show(); // переопределенная виртуальная функция
// другие переопределенные виртуальные функции
// другие перегруженные операции
protected:
// используется вместо private, если ожидается наследование
private:
// используется для деталей реализации
};
Объект абстрактного класса не может быть аргументом функции, однако
аргументом может быть указатель на абстрактный класс. В этом случае появляется возможность передавать в вызываемую функцию в качестве фактического
параметра значение указателя на производный объект, заменяя им указатель на
абстрактный базовый класс. Таким образом мы получаем полиморфные объекты.
15
Порядок выполнения работы
1. Определить иерархию классов (в соответствии с вариантом).
2. Определить в классе статическое свойство − указатель на начало связанного
списка объектов и статическую функцию для просмотра списка.
3. Реализовать классы.
4. Написать демонстрационную программу, в которой создаются объекты различных классов и помещаются в список, после чего список просматривается.
5. Сделать соответствующие методы не виртуальными и проверить их работоспособность.
6. Реализовать вариант, когда объект добавляется в список при создании, т.е. в
конструкторе.
Методические указания
Для определения иерархии классов связать отношением наследования
классы по заданию. Из перечисленных классов выбрать один, который будет
стоять во главе иерархии. Это абстрактный класс.
Определить в классах все необходимые конструкторы и деструктор.
Компонентные данные класса специфицировать как protected.
Пример определения статических компонентов:
static person* begin; // указатель на начало списка
static void print(void); // просмотр списка
Статическое свойство инициализировать вне определения класса, в глобальной области.
Для добавления объекта в список предусмотреть метод класса, т.е. объект
сам добавляет себя в список. Например, a.Add() − объект a добавляет себя в
список.
Включение объекта в список можно выполнять при создании объекта, т.е.
поместить операторы включения в конструктор. В случае иерархии классов,
включение объекта в список должен выполнять только конструктор базового
класса.
Список просматривается путем вызова виртуального метода Show каждого объекта.
Статический метод просмотра списка вызывается не через объект, а через
класс.
Определение классов, их реализация, демонстрационная программа помещаются в отдельные файлы.
16
ВАРИАНТЫ ЗАДАНИЙ
1. Студент, преподаватель, персона, завкафедрой.
2. Служащий, персона, рабочий, инженер.
3. Рабочий, кадры, инженер, администрация.
4. Деталь, механизм, изделие, узел.
5. Организация, страховая компания, судостроительная компания, завод.
6. Журнал, книга, печатное издание, учебник.
7. Тест, экзамен, выпускной экзамен, испытание.
8. Место, область, город, мегаполис.
9. Игрушка, продукт, товар, молочный продукт.
10. Квитанция, накладная, документ, чек.
11. Автомобиль, поезд, транспортное средство, экспресс.
12. Двигатель, двигатель внутреннего сгорания, дизель, турбореактивный двигатель.
13. Республика, монархия, королевство, государство.
14. Млекопитающие, парнокопытные, птицы, животное.
15. Корабль, пароход, парусник, корвет.
ЛАБОРАТОРНАЯ РАБОТА №3.
МОДЕЛЬ ВАРИАНТОВ ИСПОЛЬЗОВАНИЯ
ЦЕЛЬ И ЗАДАНИЕ
Цель работы
Получить практические навыки формализации требований к программной системе и представления их в виде диаграммы вариантов использования
языка UML в IBM Rational Rose.
Задание
Разработать диаграмму вариантов использования на заданную тему. Построение диаграммы разбивается на следующие этапы.
1. Идентификация вариантов использования как неделимых единиц последовательности действий актанта и системы.
2. Анализ вариантов использования с целью определения обобщений,
расширений и включений.
3. Разработка спецификаций вариантов использования.
17
КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ
Процесс формулирования функций системы можно частично отнести к
процессу проектирования, поскольку он определяет функциональность будущей системы, что, в свою очередь, уже на этапе анализа требований заставляет
задумываться об архитектуре системы и об элементах пользовательского интерфейса. И этот подход верен: он позволяет безболезненно перейти от этапа к
этапу и поддерживает итеративную модель разработки программных систем.
Метод вариантов использования (прецедентов) является частью методологии объектно-ориентированного проектирования. Это метод анализа и проектирования сложных систем, представляющий собой способ описания поведения
системы с точки зрения того, как различные пользователи взаимодействуют с
ней для достижения своих целей. Такой ориентированный на пользователя подход предоставляет возможность исследовать различные варианты поведения
системы при раннем привлечении пользователя.
Вариант использования – это функциональный связный блок, выраженный в виде транзакции между актантом и системой (рис. 3.1). Вариант использования описывает последовательность действий, выполняемых системой с целью получения полезного результата пользователем системы. Актантом называют пользователя системы (человек, другая система).
Вариант использования
(3)
Актант
Актанта
(пользователь)
(пользователь)
Вариант использования
(прецедент)
Вариант использования
(4)
(1)
Вариант использования
(2)
Вариант использования
(5)
Обобщение
Расширение (обощ ение)
Использование
Рис. 3.1. Обозначения в модели вариантов использования
Между вариантами использования и актантами существует связь, которая
показывает, какие функции системы доступны каждому пользователю. Кроме
того, в модели вариантов использования есть связи между самими вариантами
18
использования. В соответствии со стандартом языка UML таких связей достаточно много.
В данном пособии будут рассмотрены наиболее часто употребляемые
связи при построении модели – это обобщение, расширение и использование.
Обобщение (наследование) применяется, если поведение некоторых вариантов использования можно обобщить и «вынести» в отдельный вариант использования (рис. 3.2).
Движение контингента студентов
Секретарь
Сформировать
отчёт
Студенты, отчисленные по
неуспеваемости
Успеваемость студентов
Рис. 3.2. Пример связи обобщения
Расширение устанавливается, когда расширяющий вариант использования содержит последовательность действий, как и в расширяемом варианте использования, и добавляет свою собственную последовательность.
<<extend>>
Рис. 3.3. Расширение
Включение применяется в случае, если несколько вариантов использования в основном или альтернативных потоках имеют одинаковое поведение. В
отличие от обобщения использование не подразумевает обязательное наличие
общего поведения (рис. 3.4).
<<include>>
Рис. 3.4. Включение
СПЕЦИФИКАЦИЯ ВАРИАНТОВ ИСПОЛЬЗОВАНИЯ
Спецификация служит для описания последовательности действий пользователя и системы в рамках одного варианта использования. Цель разработки
спецификаций заключается в описании требований к ПО, которые позволят заказчику и разработчику системы однозначно (недвусмысленно) понимать тре19
бования. Спецификации вариантов использования позволяют проектировщикам
и программистам без дополнительных уточнений и домысливания разрабатывать систему.
Спецификации вариантов использования можно оформлять, придерживаясь разных стандартов, начиная с международных и заканчивая корпоративными. Спецификация должна включать следующие разделы:
− название варианта использования;
− краткое описание варианта использования;
− предварительные условия;
− основной поток;
− альтернативные потоки;
− специальные требования.
Основной поток
Вариант использования всегда инициируется актантом, когда последний
производит некое действие. Вариант использования должен описывать, что делает актант и что система делает в ответ; он должен выглядеть как диалог между актантом и системой.
Вариант использования должен описывать, что происходит внутри системы, а не как или почему это происходит. Если происходит обмен информацией, то нужно указать, какая информация поступает, а какая – отправляется.
Кроме того, не очень понятно, что имеется в виду, если сказать, что актант вводит информацию о клиенте; лучше сказать, что актант вводит имя и адрес клиента. Для того чтобы не делать вариант использования очень сложным и не запутаться в деталях, полезно использовать глоссарий, где можно определить, что
понимается под информацией о клиенте.
Простые альтернативы можно описать в тексте варианта использования.
Если для описания того, что происходит в альтернативном случае, достаточно
нескольких предложений, следует сделать это непосредственно в разделе, посвященном основному потоку событий. Если альтернативные потоки более
сложные, нужно использовать отдельный раздел «Альтернативные потоки».
Иногда рисунок информативнее многих слов. Если это поможет добиться
большей ясности, можно включать в вариант использования графические описания интерфейсов пользователя, потоков процессов или другие рисунки. Если
для представления сложного процесса принятия решения необходимо использовать формальные средства спецификации, такие как диаграммы деятельности, несомненно, это следует делать. Аналогично, если поведение системы зависит от состояния, то диаграмма перехода состояний лучше прояснит его, чем
это сделают страницы текста. Используйте представление, которое лучше всего
подходит для отображения вашей проблемы, но будьте осторожны с термино-
20
логией, обозначениями или рисунками, которые могут быть непонятны вашей
аудитории. Помните, что ваша задача – прояснить, а не запутать.
Альтернативные потоки
П е р в ы й а л ь т е р н а т и в н ы й п о т о к. Более сложные альтернативы нужно описывать в отдельном разделе. Следует воспринимать альтернативные потоки как варианты альтернативного поведения: каждый альтернативный
поток представляет некое альтернативное поведение (вариантов много из-за исключительных ситуаций, возникающих в основном потоке). Они могут быть
произвольной длины, которая требуется для описания связанных с альтернативным поведением событий. Когда альтернативный поток заканчивается, события основного потока продолжаются, если не оговорено противное.
Альтернативные потоки могут, в свою очередь, также состоять из подразделов.
В т о р о й а л ь т е р н а т и в н ы й п о т о к. Достаточно часто в варианте использования встречается несколько альтернативных потоков. Для большей ясности следует описывать каждую альтернативу отдельно. Использование
альтернативных потоков упрощает понимание варианта использования, а также
предотвращает декомпозицию вариантов использования на их иерархии. Следует помнить, что варианты использования – это только текстовые описания, и
их главная задача в том, чтобы документировать поведение системы ясно, сжато и понятно.
Специальные требования
Здесь обычно приводятся имеющие отношение к данному варианту использования нефункциональные требования, которые сложно описать в тексте
потока событий варианта использования. Примерами таких требований могут
служить положения законодательства и инструкций, применяемые стандарты,
атрибуты качества создаваемой системы, в том числе требования практичности,
надежности, производительности или возможности сопровождения. В данном
разделе следует также фиксировать другие требования, такие как описание операционных систем и сред, требования совместимости и ограничения проектирования.
Специальные требования включают предварительные условия варианта
использования (состояние системы, в котором она должна находиться перед началом выполнения варианта использования) и постусловия варианта использования (перечень возможных состояний системы непосредственно после завершения варианта использования).
21
ПРИМЕР СПЕЦИФИКАЦИИ ВАРИАНТА ИСПОЛЬЗОВАНИЯ
Пример приводится для варианта использования «Сформировать отчет о
рейтинге».
Краткое описание
Отчет показывает рейтинги студентов, дисциплин, специальностей, кафедр и факультетов по семестрам, годам и за все время обучения. Перед формированием отчета может быть установлен фильтр для уменьшения полезной
(необходимой в данный момент) информации.
Предварительные условия
Все данные о студентах и результатах аттестаций должны быть внесены в
базу данных.
Основной поток событий
Пользователь выбирает пункт меню – кнопку, ссылку на усмотрение проектировщика интерфейса пользователя. Система запускает форму выбора параметров отчета «Рейтинги студентов». На этой форме должны быть доступны
для выбора следующие параметры:
1. Дата формирования отчета. Отчет может быть сформирован за любую дату, но не позднее текущей. Соответственно данные, используемые для
формирования отчета, должны соответствовать указанной дате. Это означает,
что при выполнении запроса к БД необходимо учитывать даты создания обрабатываемых документов, которые не должны превышать значения, указанного
в данном параметре.
2. Факультет. Пользователь должен иметь возможность выбрать любой
факультет или все факультеты.
3. Кафедра. Пользователь должен иметь возможность выбрать любую
кафедру или все кафедры. Если в предыдущем пункте был выбран конкретный
факультет, то в список кафедр должны попасть только те, которые прикреплены к выбранному факультету.
4. Направление, специальность, специализация. Правило выбора аналогично п. 3.
5. Учебная группа. Правило выбора аналогично п. 3.
6. Студент. Правило выбора аналогично п. 3.
7. Результаты всех сессий на дату, указанную в п. 1.
8. Учебный год. Список параметров должен формироваться на основе выбранных в п. 1–6 параметров.
9. Результаты сессии. Выбирается номер семестра. Если выбран параметр п. 8, то в списке семестров должны находиться только те, которые попадают в выбранный учебный год.
22
10. Результаты аттестаций. В список аттестаций должны попасть
только те, которые соответствуют параметрам, выбранным в п. 7, 8.
После выбора на форме соответствующих параметров пользователь нажимает кнопку Сформировать отчет. Система формирует отчет в формате
MS.
КОНТРОЛЬНЫЕ ВОПРОСЫ
1.
2.
3.
4.
5.
6.
К какому стандарту относится модель вариантов использования?
Что такое вариант использования?
Какие вы знаете отношения между вариантами использования?
Что показывает связь между актантом и вариантом использования?
Опишите структуру спецификации варианта использования.
Для чего разрабатывается спецификация вариантов использования?
ЛАБОРАТОРНАЯ РАБОТА №4. ШАБЛОНЫ РАСПРЕДЕЛЕНИЯ
ОБЯЗАННОСТЕЙ
ЦЕЛЬ И ЗАДАНИЕ
Цель работы
Научиться применять шаблоны распределения обязанностей в проектировании объектно-ориентированных программных систем.
Задание
Спроектировать структуру объектно-ориентированной программной системы для одного из вариантов использования, созданного в предыдущей лабораторной работе, таким образом, чтобы к ней были применимы шаблоны распределения обязанностей.
МЕТОДИЧЕСКИЕ УКАЗАНИЯ
Шаблон проектирования – это именованная пара «проблема − решение»,
которая содержит рекомендации для применения в различных конкретных ситуациях, которую можно использовать в разных контекстах (проектах).
Шаблон состоит из:
− Имя;
− Задача (описывает то, где следует применять шаблон);
− Решение (описание структуры и поведения элементов);
− Результата (следствие применения шаблона и разного рода компромиссов).
23
GRASP – General Responsibility Assignment Software Patterns – общие
шаблоны распределения обязанностей в программной системе.
Обязанности бывают двух типов:
1. Знание:
− Наличие информации о закрытых, инкапсулированных данных;
− Наличие информации о связанных объектах;
− Наличие информации о вычисляемых величинах.
2. Действие:
− Выполнение действий самим объектом;
− Инициирование действий других объектов;
− Управление действиями других объектов.
Шаблон проектирования «Information Expert» (Информационный
эксперт)
Проблема: каков наиболее общий принцип распределения обязанностей
между объектами при объектно-ориентированном программировании?
Решение: назначить обязанность информационному эксперту, классу у
которого имеется информация, требуемая для выполнения обязанностей.
Пример. Некоторому классу необходимо знать общую сумму продажи
(рис. 4.1).
Sale
date
time
getTotal()
n
SalesLineItem
quantity
ProductSpecification
price
1
getSubTotal()
getPrice()
Рис. 4.1. Пример применения шаблона «Информационный эксперт»
Sale – класс продажи, имеет свойства: дата, время и метод getTotal − получение суммы.
SalesLineItem – класс список товаров, имеет свойство – количество товара, метод – получение промежуточной суммы.
24
ProdactSpecification – класс продукта, имеет свойство – цена и метод –
получение цены товара.
Согласно шаблону «Информационный эксперт» нужно определить объекты каких классов содержат информацию, необходимую для вычисления общей
суммы. На диаграмме коопераций (рис. 4.2) приведён пример распределения
обязанностей в соответствии с шаблоном «Информационный эксперт».
1. getSubTotal()
: Sale
:
SalesLineItem
1.1. getPrice()
:
ProductSpecification
Рис. 4.2. Диаграмма кооперации применения шаблона «Информационный эксперт»
Шаблон «Информационный эксперт» поддерживает инкапсуляцию. Соответствующее поведение системы обеспечивается несколькими классами, содержащими требуемую информацию. Это приводит к определениям классов,
которые гораздо проще понимать и поддерживать.
Шаблон проектирования «Creator» (Создатель)
Проблема: кто должен отвечать за создание нового экземпляра некоторого класса?
Решение: назначить классу В обязанность создавать экземпляры класса А
если выполняется одно из следующих условий.
1. Класс В агрегирует объекты класса А.
2. Класс В активно использует объекты класса А.
3. Класс В обладает данными инициализации, необходимыми для создания
объектов класса А.
Пример. Кто должен отвечать за создание нового экземпляра класса
SalesLineItem (рис. 4.3)?
Sale – класс продажи, имеет свойства: дата, время и метод getTotal - получение суммы.
SalesLineItem – класс списка товаров, имеет свойство – количество товара, метод – получение промежуточной суммы.
ProdactSpecification – класс продукта, имеет свойство – цена, метод – получение цены товара.
25
Register – класс, отвечающий за создание нового экземпляра класса
SalesLineItem.
Sale
date
time
Register
getTotal()
n
SalesLineItem
quantity
ProductSpecification
price
1
getSubTotal()
getPrice()
Рис. 4.3. Диаграмма классов для шаблона «Создатель»
Класс Sale является хорошим кандидатом для создания объектов класса
SalesLineItem, так как он активно использует его объекты и является их агрегатом (рис. 4.4).
: Register
: Sale
1. makeLineItem(quant)
1.1. *create
: SalesLineItem
Рис. 4.4. Диаграмма последовательностей для шаблона «Создатель»
Применение этого шаблона не повышает степени связанности, поскольку
созданный объект, как правило, является видимым для класса-создателя посредством имеющихся ассоциаций.
Шаблон проектирования «Low Coupling» (Слабое связывание)
Проблема: как обеспечить незначительное влияние изменений и повысить
возможность повторного использования?
Решение: распределить обязанности таким образом, чтобы степень связывания оставалась низкой.
Степень связывания – это мера, определяющая, насколько жёстко один
элемент связан с другими элементами, либо каким количеством данных о других элементах он обладает (рис. 4.5).
26
А
Б
Рис. 4.5. Степень связывания
А – слабое связывание; Б – сильное связывание
Пример. Необходимо создать экземпляр класса Payment и связать его с
экземпляром класса Sale (рис. 4.6−4.9).
Payment
Sale
date
time
Register
getTotal()
n
SalesLineItem
quantity
1
getSubTotal()
ProductSpecification
price
getPrice()
Рис. 4.6. Диаграмма классов для шаблона «Слабое связывание». Вариант 1
1.
1.1. p:=create
p:
TPayment
: TRegister
1.2. addPayment(p)
: TSale
Рис. 4.7. Диаграмма кооперации для шаблона «Слабое связывание». Вариант 1
27
Payment
Sale
date
time
Register
getTotal()
n
SalesLineItem
quantity
1
getSubTotal()
ProductSpecification
price
getPrice()
Рис. 4.8. Диаграмма классов для шаблона «Слабое связывание». Вариант 2
1. makePayment()
: Sale
: Register
2. create
p : Payment
Рис. 4.9. Диаграмма кооперации для шаблона «Слабое связывание». Вариант 2
В обоих вариантах предполагается, что в конечном итоге объекту Sale
должно быть известно о существовании объекта Payment. При использовании
первого варианта, когда объект Payment создается с помощью объекта Register,
между этими двумя объектами добавляется новая связь, тогда как второй способ степень связанности не усиливает.
Преимущества шаблона. Изменение компонентов мало сказывается на
других объектах. Принципы работы и функции компонентов можно понять, не
изучая другие объекты. Удобство повторного использования.
Шаблон проектирования «High Cohesion» (Высокое зацепление)
Шаблон «Высокое зацепление» − обратная сторона шаблона «Слабое связывание», поэтому они должны использоваться вместе.
Проблема: как обеспечить возможность управления сложностью?
28
Решение: распределение обязанностей, поддерживающее высокую степень зацепления.
Зацепление – это мера связанности и сфокусированности обязанностей
класса. Класс обладает высокой степенью зацепления, если его обязанности
тесно связаны между собой. Класс с низкой степенью зацепления выполняет
много разнородных функций.
На диаграмме (рис. 4.10) платежи выполняет объект Register, который
частично несет ответственность за выполнение операции MakePayment.
: Register
1. makePayment()
: Sale
1.1. makePayment
1.1.1. create
: Payment
Рис. 4.10. Диаграмма последовательностей для обязанности makePayment (вариант 1)
На диаграмме (рис. 4.11) обязанность платежа делегирована объекту Sale.
Благодаря этому поддерживается более высокая степень зацепления объекта
Register.
: Register
: Sale
1. makePayment()
1.1. create
p : Payment
1.2. addPayment(p)
Рис. 4.11. Диаграмма последовательностей для обязанности makePayment (вариант 2)
Преимущества шаблона:
− повышается легкость и простота проектных решений;
− упрощается поддержка и доработка;
− зачастую обеспечивается слабое связывание;
− улучшаются возможности повторного использования кода.
29
ЛАБОРАТОРНАЯ РАБОТА №5. ПОРОЖДАЮЩИЕ ШАБЛОНЫ
ЦЕЛЬ И ЗАДАНИЕ
Цель работы
Научиться применять порождающие шаблоны в проектировании объектно-ориентированных программных систем.
Задание
Выполнить рефакторинг реализации варианта использования, созданного
в лабораторной работе №3. Применить порождающие шаблоны для улучшения
архитектуры программной системы. Использовать нотацию диаграммы последовательностей для иллюстрации взаимодействия объектов.
МЕТОДИЧЕСКИЕ УКАЗАНИЯ
Эта одна из категорий, на которые разбивают шаблоны проектирования.
В свою очередь эту категорию делят еще на два типа − паттерны порождающие
объекты и паттерны порождающие классы. Первые создаются с помощью другого объекта, вторые с помощью наследования изменяют класс создаваемого
объекта.
Основная идея порождающих паттернов заключается в том, что инстанцирование объектов происходит «за кадром», они скрывают в себе какие именно классы используются в приложении и детали их реализации, оставляя только
интерфейсы к ним. По идее это позволяет собрать полностью рабочее приложение из различных заготовленных заранее объектов, но по своему опыту скажу, что это практически невозможно без использования других типов шаблонов. Их всего 5.
1. Абстрактная фабрика (Abstract Factory).
2. Одиночка (Singleton).
3. Прототип (Prototype).
4. Строитель (Builder).
5. Фабричный метод (Factory Method).
30
Абстрактная фабрика (Abstract Factory)
Проблема
Создать семейство взаимосвязанных или взаимозависимых объектов (не специфицируя их конкретных классов).
Решение
Создать абстрактный класс, в котором объявлен интерфейс для создания конкретных классов.
Пример
Какой класс должен отвечать за создание объектов – адаптеров. Если подобные объекты создаются неким объектом уровня предметной области, то будет нарушен принцип разделения обязанностей.
Изолирует конкретные классы. Поскольку «Абстрактная фабрика»
инкапсулирует ответственность за создание классов и сам процесс
Преимущества их создания, то она изолирует клиента от деталей реализации классов. Упрощена замена «Абстрактной фабрики», поскольку она используется в приложении только один раз при инстанцировании.
Недостатки
Интерфейс «Абстрактной фабрики» фиксирует набор объектов, которые можно создать. Расширение «Абстрактной фабрики» для изготовления новых объектов часто затруднительно.
Одиночка (Singleton)
Проблема
Какой специальный класс должен создавать «Абстрактную фабрику» и как получить к ней доступ? Необходим лишь один экземпляр
специального класса, различные объекты должны обращаться к
этому экземпляру через единственную точку доступа.
Решение
Создать класс и определить статический метод класса, возвращающий этот единственный объект.
Разумнее создавать именно статический экземпляр специального
класса, а не объявить требуемые методы статическими, поскольку
при использовании методов экземпляра можно применить механизм
наследования и создавать подклассы. Статические методы в языках
Рекомендации
программирования не полиморфны и не допускают перекрытия в
производных классах. Решение на основе создания экземпляра является более гибким, поскольку впоследствии может потребоваться
уже не единственный экземпляр объекта, а несколько.
31
Прототип (Prototype)
Проблема
Система не должна зависеть от того, как в ней создаются, компонуются
и представляются объекты.
Создавать новые объекты с помощью паттерна - прототипа. «Прототип»
объявляет интерфейс для клонирования самого себя. «Клиент» создает
новый объект, обращаясь к «Прототипу» с запросом клонировать «Прототип».
Решение
Строитель (Builder)
Проблема
Отделить конструирование сложного объекта от его представления, так чтобы в результате одного и того же конструирования
могли получаться различные представления. Алгоритм создания
сложного объекта не должен зависеть от того, из каких частей состоит объект и как они стыкуются между собой.
Решение
«Клиент» создает объект - распорядитель «Директор» и конфигурирует его объектом – «Строителем». «Директор» уведомляет
«Строителя» о том, что нужно построить очередную часть «Продукта». «Строитель» обрабатывает запросы «Директора» и добавляет новые части к «Продукту», затем «Клиент» забирает «Продукт» у «Строителя». Диаграммы классов и последовательностей
для решения приведены на рисунках 5.1−5.2
Преимущества Объект «Строитель» предоставляет объекту «Директор» абстрактный интерфейс для конструирования «Продукта», за которым может скрыть представление и внутреннюю структуру продукта, и ,
кроме того, процесс сборки «продукта». Для изменения внутреннего представления «Продукта» достаточно определить новый вид
«Строителя». Данный паттерн изолирует код, реализующий создание объекта и его представление.
32
Рис. 5.1. Диаграмма классов шаблона «Строитель»
Рис. 5.2. Диаграмма последовательностей шаблона «Строитель»
Фабричный метод (Factory Method )
Проблема
Решение
Определить интерфейс для создания объекта, но оставить подклассам решение о том, какой класс инстанцировать, то есть, делегировать инстанцирование подклассам.
Абстрактный класс «Создатель» объявляет Фабричный метод, возвращающий объект типа «Продукт» (абстрактный класс, определяющий интерфейс объектов, создаваемых фабричным методом).
«Создатель также может определить реализацию по умолчанию
Фабричного метода, который возвращает «Конкретный продукт».
«Конкретный создатель» замещает Фабричный метод, возвращающий объект «Конкретный продукт». «Создатель» «полагается» на
свои подклассы в определении Фабричного метода, возвращающего объект «Конкретный продукт».
33
Преимущества Избавляет проектировщика от необходимости встраивать в код зависящие от приложения классы.
Недостатки
Возникает дополнительный уровень подклассов.
ЛАБОРАТОРНАЯ РАБОТА №6. ШАБЛОНЫ ПОВЕДЕНИЯ
ЦЕЛЬ И ЗАДАНИЕ
Цель работы
Научиться применять шаблоны поведения в проектировании объектноориентированных программных систем.
Задание
Выполнить рефакторинг реализации варианта использования, созданного
в лабораторной работе №3. Применить шаблоны поведения для повышения устойчивости работы программной системы. Использовать нотацию диаграмм
кооперации и/или последовательностей для иллюстрации взаимодействия объектов.
МЕТОДИЧЕСКИЕ УКАЗАНИЯ
Основная идея паттернов этого типа − взаимодействие объектов и классов между собой. Но они также делятся на два уровня − паттерны поведения
уровня класса и паттерны поведения уровня объекта. Здесь самое сложное это
добиться наименьшей степени связанности компонентов системы друг с другом, потому что почти все объекты должны знать о существовании других и нести в себе эту информацию. Отсюда и появились такие сложные паттерны как
«Посредник» и «Цепочка обязанностей». Их 11.
1. Интерпретатор (Interpreter).
2. Итератор (Iterator).
3. Команда (Command).
4. Наблюдатель (Observer).
5. Посетитель (Visitor).
34
6. Посредник (Mediator).
7. Состояние (State).
8. Стратегия (Strategy).
9. Хранитель (Memento).
10. Цепочка обязанностей (Chain of Responsibility).
11. Шаблонный метод (Template Method).
Интерпретатор (Interpreter )
Проблема
Решение
Пример
Имеется часто встречающаяся, подверженная изменениям задача.
Создать интерпретатор, который решает данную задачу.
Задача поиска строк по образцу может быть решена посредством
создания интерпретатора, определяющего грамматику языка.
«Клиент» строит предложение в виде абстрактного синтаксического дерева, в узлах которого находятся объекты классов «Нетерминальное выражение» и «Терминальное выражение» (рекурсивное),
затем «Клиент» инициализирует контекст и вызывает операцию
Разобрать(Контекст). На каждом узле типа «Нетерминальное выражение» определяется операция Разобрать для каждого подвыражения. Для класса «Терминальное выражение» операция Разобрать
определяет базу рекурсии. «Абстрактное выражение» определяет
абстрактную операцию Разобрать, общую для всех узлов в абстрактном синтаксическом дереве. «Контекст» содержит информацию, глобальную по отношению к интерпретатору.
Преимущества Грамматику становится легко расширять и изменять, реализации
классов, описывающих узлы абстрактного синтаксического дерева
похожи (легко кодируются). Можно легко изменять способ вычисления выражений.
Недостатки
Сопровождение грамматики с большим числом правил затруднительно.
35
Итератор (Iterator)
Проблема
Составной объект, например, список, должен предоставлять доступ
к своим элементам (объектам), не раскрывая их внутреннюю структуру, причем перебирать список требуется по-разному в зависимости от задачи.
Создается класс «Итератор», который определяет интерфейс для
доступа и перебора элементов, «Конкретный итератор» реализует
интерфейс класса «Итератор» и следит за текущей позицией при
обходе «Агрегата». «Агрегат» определяет интерфейс для создания
объекта - итератора. «Конкретный агрегат» реализует интерфейс
создания итератора и возвращает экземпляр класса «Конкретный
Итератор», «Конкретный итератор» отслеживает текущий объект в
агрегате и может вычислить следующий объект при переборе.
Решение
Преимущества
Поддерживает различные способы перебора агрегата, одновременно
могут быть активны несколько переборов.
Команда (Command)
Проблема
Необходимо послать объекту запрос, не зная о том, выполнение какой операции запрошено и кто будет получателем.
Решение
Инкапсулировать запрос как объект. «Клиент» создает объект
«Конкретная команда», который вызывает операции получателя для
выполнения запроса, «Инициатор» отправляет запрос, выполняя
операцию «Команды» Выполнить(). «Команда» объявляет интерфейс для выполнения операции, «Конкретная команда» определяет
связь между объектом «Получатель» и операцией Действие(), и,
кроме того, реализует операцию Выполнить() путем вызова соответствующих операций объекта «Получатель». «Клиент» создает
экземпляр класса «Конкретная команда» и устанавливает его получателя, «Инициатор» обращается к команде для выполнения запроса, «Получатель» (любой класс) располагает информацией о способах выполнения операций, необходимых для выполнения запроса.
36
Паттерн «Команда» разрывает связь между объектом, инициирующим операции, и объектом, имеющим информацию о том, как ее
Преимущества
выполнить, кроме того создается объект «Команда», который можно расширять и манипулировать им как объектом.
Наблюдатель (Observer)
Один объект («Подписчик») должен знать об изменении состояний или
Проблема некоторых событиях другого объекта. При этом необходимо поддерживать низкий уровень связывания с объектом - «Подписчиком».
Решение
Определить интерфейс «Подписки». Объекты - подписчики реализуют
этот интерфейс и динамически регистрируются для получения информации о некотором событии. Затем при реализации условленного события
оповещаются все объекты - подписчики.
Посетитель (Visitor)
Проблема
Над каждым объектом некоторой структуры выполняется операция.
Определить новую операцию, не изменяя классы объектов.
Решение
Клиент, использующий данный паттерн, должен создать объект
класса «Конкретный посетитель», а затем посетить каждый элемент
структуры. «Посетитель» объявляет операцию «Посетить» для каждого класса «Конкретный элемент» (имя и сигнатура данной операции идентифицируют класс, элемент которого посещает «Посетитель» - то есть, посетитель может обращаться к элементу напрямую). «Конкретный посетитель» реализует все операции, объявленные в классе «Посетитель». Каждая операция реализует фрагмент
алгоритма, определенного для класса соответствующего объекта в
структуре.
Класс «Конкретный посетитель» предоставляет контекст для этого
алгоритма и сохраняет его локальное состояние. «Элемент» определяет операцию «Принять», которая принимает «Посетителя» в качестве аргумента, «Конкретный элемент» реализует операцию
«Принять», которая принимает «Посетителя» в качестве аргумента.
«Структура обьекта» может перечислить свои аргументы и предоставить посетителю высокоуровневый интерфейс для посещения
37
своих элементов.
Логично использовать, если в структуре присутствуют объекты
многих классов с различными интерфейсами, и необходимо выполРекомендации нить над ними операции, зависящие от конкретных классов, или если классы, устанавливающие структуру объектов изменяются редко, но новые операции над этой структурой добавляются часто.
Преимущества
Упрощается добавление новых операций, объединяет родственные
операции в классе «Посетитель».
Недостатки
Затруднено добавление новых классов «Конкретный элемент», поскольку требуется объявление новой абстрактной операции в классе
«Посетитель».
Посредник (Mediator)
Проблема
Обеспечить взаимодействие множества объектов, сформировав при
этом слабую связанность и избавив объекты от необходимости явно
ссылаться друг на друга.
Решение
Создать объект инкапсулирующий способ взаимодействия множества объектов.
Пример
«Посредник» определяет интерфейс для обмена информацией с
объектами «Коллеги», «Конкретный посредник» координирует действия объектов «Коллеги». Каждый класс «Коллеги» знает о своем
38
объекте «Посредник», все «Коллеги» обмениваются информацией
только с посредником, при его отсутствии им пришлось бы обмениваться информацией напрямую. «Коллеги» посылают запросы посреднику и получают запросы от него. «Посредник» реализует кооперативное поведения, пересылая каждый запрос одному или нескольким «Коллегам».
Преимущества
Устраняется связанность между «Коллегами», централизуется
управление.
БИБЛИОГРАФИЧЕСКИЙ СПИСОК
1. Программирование на языке высокого уровня [Электронный ресурс] :
учебник для вузов / С. В. Синицын, А. С. Михайлов, О. И. Хлытчиев. - М. :
Академия, 2010. - 400 с. : ил. - (Высшее профессиональное образование). - Загл.
с титул. экрана. - Электрон. версия печатного издания. - Формат: DJVU; размер:
5 Мб; доступ: локальная сеть СФУ. - Библиогр.: с. 385-388. - Б. ц.
2. Программирование на языке высокого уровня. Программирование на
языке OBJECT PASCAL : учеб. пособие / Т. И. Немцова, С. Ю. Голова, И. В.
Абрамова ; ред. Л. Г. Гагарина. - М. : Форум-Инфра-М, 2011. - 495 с.
3. Объектно-ориентированное программирование : учебник для студентов вузов / О. М. Масловская. - Одесса : Укрполиграф, 2007. - 246 с.
4. Влиссидес Дж. Применение шаблонов проектирования. Дополнительные штрихи. – М.: Издательский дом «Вильямс», 2003. – 144 с.
5. Шаллоуей Алан, Тротт Джеймс. Шаблоны проектирования. Новый
подход к объектно-ориентированному анализу и проектированию. – М.: Издательский дом «Вильямс», 2002. – 288 с.
39
Документ
Категория
Без категории
Просмотров
34
Размер файла
642 Кб
Теги
1371, метод, учеб, основы, лаб, проектирование, объектно, пособие, программирование
1/--страниц
Пожаловаться на содержимое документа