c++ Базовый. Занятие 17

Post on 21-Mar-2017

80 Views

Category:

Education

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Модуль 4: Дополнительные темы объектно-ориентированного программирования.

Темы лекции: Структурные и поведенческие шаблоны проектирования.

Практическое задание: Структурные и поведенческие шаблоны проектирования.

Тренер: Игорь Шкулипа, к.т.н.

C++ Базовый. Занятие 17

http://www.slideshare.net/IgorShkulipa 2

Структурные шаблоны проектирования

http://www.slideshare.net/IgorShkulipa 3

Структурные шаблоны проектирования

◦ Adapter представляет собой программную обертку над ужесуществующими классами и предназначен для преобразования ихинтерфейсов к виду, пригодному для последующего использованияв новом программном проекте.

◦ Bridge отделяет абстракцию от реализации так, что то и другоеможно изменять независимо.

◦ Composite группирует схожие объекты в древовидные структуры.Рассматривает единообразно простые и сложные объекты.

◦ Decorator используется для расширения функциональностиобъектов. Являясь гибкой альтернативой порождению классов,паттерн Decorator динамически добавляет объекту новыеобязанности.

◦ Facade предоставляет высокоуровневый унифицированныйинтерфейс к набору интерфейсов некоторой подсистемы, чтооблегчает ее использование.

◦ Flyweight использует разделение для эффективной поддержкимножества объектов.

◦ Proxy замещает другой объект для контроля доступа к нему.

http://www.slideshare.net/IgorShkulipa 4

Адаптер

Паттерн Adapter, представляет собой программную обертку надсуществующими классами, преобразуя их интерфейсы к виду,пригодному для последующего использования.

Пусть класс, интерфейс которого нужно адаптировать к нужномувиду, имеет имя Adaptee. Для решения задачи преобразованияего интерфейса паттерн Adapter вводит следующую иерархиюклассов:

◦ Виртуальный базовый класс Target. Здесь объявляетсяпользовательский интерфейс подходящего вида. Только этотинтерфейс доступен для пользователя.

◦ Производный класс Adapter, реализующий интерфейс Target.В этом классе также имеется указатель или ссылка наэкземпляр Adaptee. Паттерн Adapter использует этотуказатель для перенаправления клиентских вызовов вAdaptee. Так как интерфейсы Adaptee и Target несовместимымежду собой, то эти вызовы обычно требуютпреобразования.

http://www.slideshare.net/IgorShkulipa 5

Пример. Преобразование строки в структуру

class InputStringFullName {

protected:

string _strText;

public:

InputStringFullName() {

_strText="";

}

void Input() {

cout<<"Input Full Name (Surname Name MiddleName): ";

char* cstr=new char;

cin.getline(cstr, 9999, '\n');

_strText=string(cstr);

}

string GetText(){return _strText;}

};

http://www.slideshare.net/IgorShkulipa 6

Класс структуры

class FullName {

private:

string _strName; string _strSurname; string _strMiddle;

public:

FullName(string strSurname, string strName, string strMiddleName) {

_strName=strName; _strSurname=strSurname; _strMiddle=strMiddleName;

}

void Print() {

cout<<"Name: "<<_strName<<"\n";

cout<<"Middle Name: "<<_strMiddle<<"\n";

cout<<"Surname: "<<_strSurname<<"\n";

}

string GetName() {return _strName;}

string GetSurname() {return _strSurname;}

string GetMiddle() {return _strMiddle;}

void SetName(string strText) {_strName=strText;}

void SetSurname(string strText) {_strSurname=strText;}

void SetMiddle(string strText) {_strMiddle=strText;}

};

http://www.slideshare.net/IgorShkulipa 7

Класс-адаптер

class FullNameAdapter: public InputStringFullName

{

public:

FullNameAdapter(InputStringFullName* stringFullName)

{

_strText=stringFullName->GetText();

}

FullName* GetFullName()

{

unsigned iFirstSpace=_strText.find_first_of(" ");

string strSurname=_strText.substr(0,iFirstSpace);

unsigned iSecondSpace=

_strText.substr(iFirstSpace+1).find_first_of(" ")+iFirstSpace+1;

string strName=_strText.substr(iFirstSpace, iSecondSpace-iFirstSpace);

string strMiddle=_strText.substr(iSecondSpace);

return new FullName(strSurname, strName, strMiddle);

}

};

http://www.slideshare.net/IgorShkulipa 8

Использование адаптера

int main()

{

InputStringFullName* isfn=new InputStringFullName();

isfn->Input();

FullNameAdapter* fna=new FullNameAdapter(isfn);

FullName* fn=fna->GetFullName();

fn->Print();

}

Результат:Input Full Name (Surname Name MiddleName): Ivanov Petr Sidorovich

Name: Petr

Middle Name: Sidorovich

Surname: Ivanov

http://www.slideshare.net/IgorShkulipa 9

Bridge

Используется для того, чтобы разделять абстракцию иреализацию так, чтобы они могли изменяться независимо.

http://www.slideshare.net/IgorShkulipa 10

Реализация. Классы реализаторов с общим интерфейсом

class Iimplementor {

public: virtual void Operation()=0;

};

class Implementor1 : public Iimplementor {

public: virtual void Operation() {

cout<<"Implementor 1\n";

} };

class Implementor2 : public Iimplementor {

public: virtual void Operation() {

cout<<"Implementor 2\n";

} };

http://www.slideshare.net/IgorShkulipa 11

Класс-абстракция

class Abstraction

{

protected:

IImplementor* _implementor;

public:

Abstraction(){}

void SetImplementor(IImplementor* implementor)

{

_implementor=implementor;

}

virtual void Operation()

{

_implementor->Operation();

}

};

http://www.slideshare.net/IgorShkulipa 12

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

int main()

{

Abstraction* abstr=new Abstraction();

abstr->SetImplementor(new Implementor1());

abstr->Operation();

abstr->SetImplementor(new Implementor2());

abstr->Operation();

}

Результат:Implementor 1

Implementor 2

http://www.slideshare.net/IgorShkulipa 13

Фасад

Паттерн Facade предоставляет унифицированный интерфейсвместо набора интерфейсов некоторой подсистемы. Facadeопределяет интерфейс более высокого уровня, упрощающийиспользование подсистемы.

Паттерн Facade "обертывает" сложную подсистему более простыминтерфейсом.

http://www.slideshare.net/IgorShkulipa 14

Реализация. Подсистема 1

class ITeacher {

public:

virtual string GetLecture()=0;

};

class CppTeacher: public ITeacher {

public:

virtual string GetLecture() {

return string("This is C++ Lecture");

} };

class CsTeacher: public ITeacher {

public:

virtual string GetLecture() {

return string("This is C# Lecture");

} };

http://www.slideshare.net/IgorShkulipa 15

Подсистема 2

class IAdministration {

public:

virtual string GetAdvice()=0;

};

class Director: public IAdministration {

public:

virtual string GetAdvice() {

return string("Director's Advice");

} };

class Administrator: public IAdministration {

public:

virtual string GetAdvice() {

return string("Administrator's Advice");

} };

http://www.slideshare.net/IgorShkulipa 16

Фасадclass Facade {

public:

string GetCppLecture() {

_teacher=new CppTeacher();

return _teacher->GetLecture();

}

string GetCsLecture() {

_teacher=new CsTeacher();

return _teacher->GetLecture();

}

string GetDirectorAdvice() {

_administration=new Director();

return _administration->GetAdvice();

}

string GetAdministratorAdvice() {

_administration=new Administrator();

return _administration->GetAdvice();

}

private:

ITeacher* _teacher;

IAdministration* _administration;

};

http://www.slideshare.net/IgorShkulipa 17

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

int main()

{

Facade* facade=new Facade();

cout<<facade->GetAdministratorAdvice().c_str()<<"\n";

cout<<facade->GetCppLecture().c_str()<<"\n";

cout<<facade->GetCsLecture().c_str()<<"\n";

cout<<facade->GetDirectorAdvice().c_str()<<"\n";

}

Результат:Administrator's Advice

This is C++ Lecture

This is C# Lecture

Director's Advice

http://www.slideshare.net/IgorShkulipa 18

Паттерны для самостоятельного изучения

Паттерн Composite группирует схожие объекты в древовидныеструктуры. Рассматривает единообразно простые и сложныеобъекты.

Паттерн Decorator используется для расширенияфункциональности объектов. Являясь гибкой альтернативойпорождению классов, паттерн Decorator динамическидобавляет объекту новые обязанности.

Паттерн Flyweight использует разделение для эффективнойподдержки множества объектов.

Паттерн Proxy замещает другой объект для контроля доступа кнему.

http://www.slideshare.net/IgorShkulipa 19

Шаблоны поведения

http://www.slideshare.net/IgorShkulipa 20

Шаблоны поведения

Паттерн Chain of Responsibility позволяет обработать запроснескольким объектам-получателям. Получатели связываются вцепочку, и запрос передается по цепочке, пока не будет обработанкаким-то объектом. Паттерн Chain of Responsibility позволяет такжеизбежать жесткой зависимости между отправителем запроса и егополучателями.

Паттерн Command преобразовывает запрос на выполнение действия вотдельный объект-команду. Это придает системе гибкость: позволяетосуществлять динамическую замену команд, использовать сложныесоставные команды, осуществлять отмену операций.

Паттерн Iterator предоставляет механизм обхода элементов составныхобъектов (коллекций) не раскрывая их внутреннего представления.

Паттерн Interpreter предназначен для решения повторяющихся задач,которые можно описать некоторым языком. Для этого паттернInterpreter описывает решаемую задачу в виде предложений этогоязыка, а затем интерпретирует их.

Паттерн Mediator инкапсулирует взаимодействие совокупностиобъектов в отдельный объект-посредник. Уменьшает степеньсвязанности взаимодействующих объектов - им не нужно хранитьссылки друг на друга.

http://www.slideshare.net/IgorShkulipa 21

Шаблоны поведенияПаттерн Memento получает и сохраняет за пределами объекта его

внутреннее состояние так, чтобы позже можно было восстановитьобъект в таком же состоянии.

Паттерн Observer определяет зависимость "один-ко-многим" междуобъектами так, что при изменении состояния одного объекта всезависящие от него объекты уведомляются и обновляютсяавтоматически.

Паттерн State позволяет объекту изменять свое поведение взависимости от внутреннего состояния. Создается впечатление, чтообъект изменил свой класс. Паттерн State является объектно-ориентированной реализацией конечного автомата.

Если поведение системы настраивается согласно одному из некоторогомножества алгоритму, то применение паттерна Strategy переноситсемейство алгоритмов в отдельную иерархию классов, что позволяетзаменять один алгоритм другим в ходе выполнения программы. Крометого, такую систему проще расширять и поддерживать.

Паттерн Template Method определяет основу алгоритма и позволяетподклассам изменить некоторые шаги этого алгоритма без измененияего общей структуры.

Паттерн Visitor определяет операцию, выполняемую на каждомэлементе из некоторой структуры без изменения классов этихобъектов.

http://www.slideshare.net/IgorShkulipa 22

Команда

Паттерн Command преобразовывает запрос на выполнениедействия в отдельный объект-команду. Такая инкапсуляцияпозволяет передавать эти действия другим функциям иобъектам в качестве параметра, приказывая им выполнитьзапрошенную операцию. Команда – это объект, поэтому надней допустимы любые операции, что и над объектом.

Команда используется, если:

◦ Система управляется событиями. При появлении такогособытия (запроса) необходимо выполнить определеннуюпоследовательность действий.

◦ Необходимо параметризировать объекты выполняемымдействием, ставить запросы в очередь или поддерживатьоперации отмены и повтора действий.

◦ Нужен объектно-ориентированный аналог функцииобратного вызова в процедурном программировании.

http://www.slideshare.net/IgorShkulipa 23

Пример. Интерфейс «Игра»

class IGame

{

public:

virtual void New()=0;

virtual void Start()=0;

virtual void Pause()=0;

virtual void Resume()=0;

virtual void Finish()=0;

virtual void Break()=0;

virtual void BreakAndFinish()=0;

virtual void BreakAndStart()=0;

};

http://www.slideshare.net/IgorShkulipa 24

Реализация интерфейса

class SomeGame: public IGame {

public:

virtual void New() {

cout<< "New Game.\n“; }

virtual void Start() {

cout<< "Game Started.\n“; }

virtual void Pause() {

cout<< "Game Paused.\n“; }

virtual void Resume() {

cout<< "Game Resumed.\n“; }

virtual void Finish() {

cout<< "Game Finished.\n“; }

virtual void Break() {

cout<< "Game Breaked.\n“; }

virtual void BreakAndFinish() {

this->Break(); this->Finish(); }

virtual void BreakAndStart() {

this->Break(); this->New(); this->Start(); }

};

http://www.slideshare.net/IgorShkulipa 25

Классы команд

class ICommand {

public:

ICommand(IGame* game){ _game=game; }

virtual void ExecuteCommand()=0;

virtual ~ICommand(){ delete _game;}

protected: IGame* _game;

};

class NewCommand: public ICommand {

public:

NewCommand(IGame* game):ICommand(game){}

virtual void ExecuteCommand(){

cout<<"Executing New Command...\n";

_game->New();

} };

class StartCommand: public ICommand {

public:

StartCommand(IGame* game):ICommand(game){}

virtual void ExecuteCommand() {

cout<<"Executing Start Command...\n";

_game->Start();

} };

http://www.slideshare.net/IgorShkulipa 26

Классы команд

class PauseCommand: public ICommand {

public:

PauseCommand(IGame* game):ICommand(game){}

virtual void ExecuteCommand() {

cout<<"Executing Pause Command...\n";

_game->Pause();

} };

class ResumeCommand: public ICommand {

public:

ResumeCommand(IGame* game):ICommand(game){}

virtual void ExecuteCommand() {

cout<<"Executing Resume Command...\n";

_game->Resume();

} };

class FinishCommand: public ICommand {

public:

FinishCommand(IGame* game) :ICommand(game){}

virtual void ExecuteCommand() {

cout<<"Executing Finish Command...\n";

_game->Finish();

} };

http://www.slideshare.net/IgorShkulipa 27

Классы командclass BreakCommand: public ICommand {

public:

BreakCommand(IGame* game):ICommand(game){}

virtual void ExecuteCommand() {

cout<<"Executing Break Command...\n";

_game->Break();

} };

class BreakAndFinishCommand: public ICommand {

public:

BreakAndFinishCommand(IGame* game):ICommand(game){}

virtual void ExecuteCommand() {

cout<<"Executing Break And Finish Command...\n";

_game->BreakAndFinish();

} };

class BreakAndStartCommand: public ICommand {

public:

BreakAndStartCommand(IGame* game) :ICommand(game){}

virtual void ExecuteCommand() {

cout<<"Executing Break And Start Command...\n";

_game->BreakAndStart();

} };

http://www.slideshare.net/IgorShkulipa 28

Использование команд

int main()

{

IGame* someGame=new SomeGame();

ICommand* command[10];

command[0]=new NewCommand(someGame);

command[1]=new StartCommand(someGame);

command[2]=new BreakCommand(someGame);

command[3]=new NewCommand(someGame);

command[4]=new StartCommand(someGame);

command[5]=new BreakAndStartCommand(someGame);

command[6]=new PauseCommand(someGame);

command[7]=new ResumeCommand(someGame);

command[8]=new PauseCommand(someGame);

command[9]=new BreakAndFinishCommand(someGame);

for (int i=0;i<10;i++)

{

command[i]->ExecuteCommand();

}

}

Результат:Executing New Command...

New Game.

Executing Start Command...

Game Started.

Executing Break Command...

Game Breaked.

Executing New Command...

New Game.

Executing Start Command...

Game Started.

Executing Break And Start Command...

Game Breaked.

New Game.

Game Started.

Executing Pause Command...

Game Paused.

Executing Resume Command...

Game Resumed.

Executing Pause Command...

Game Paused.

Executing Break And Finish Command...

Game Breaked.

Game Finished.

http://www.slideshare.net/IgorShkulipa 29

Chain of Responsibility

Паттерн Chain of Responsibility позволяет избежать жесткойзависимости отправителя запроса от его получателя, при этомзапрос может быть обработан несколькими объектами.Объекты-получатели связываются в цепочку. Запроспередается по этой цепочке, пока не будет обработан.

Вводит конвейерную обработку для запроса с множествомвозможных обработчиков.

Объектно-ориентированный связанный список с рекурсивнымобходом.

http://www.slideshare.net/IgorShkulipa 30

Общая схема паттерна

Клиент

Обработчик 1

Обработчик 2

Обработчик 3

Обработчик ...

Обработчик n

http://www.slideshare.net/IgorShkulipa 31

Реализация цепочки. Классы событий

class IEvent{

public: virtual string GetEventType(){return _strEventType;}

protected: string _strEventType;

};

class Event1: public IEvent {

public: Event1(){_strEventType="Event1";}};

class Event2: public IEvent {

public: Event2(){_strEventType="Event2";}};

class Event3: public IEvent {

public: Event3(){_strEventType="Event3";}};

class Event4: public IEvent{

public: Event4(){_strEventType="Event4";}};

class Event5: public IEvent {

public: Event5(){_strEventType="Event5";}};

class Event6: public IEvent {

public: Event6(){_strEventType="Event6";}};

http://www.slideshare.net/IgorShkulipa 32

Базовый класс-обработчик

class BaseHandler {

public:

BaseHandler(){_next=NULL;}

virtual void Handle(IEvent* ev) {

if (_event->GetEventType()==ev->GetEventType()) {

cout<<_event->GetEventType()<<" successfully handled.\n";

} else {

cout<<"Sending event to next Handler...\n";

if (_next)

_next->Handle(ev);

else

cout<<"Unknown event. Can't handle.\n";

}}

protected:

void SetNextHandler(BaseHandler* newHandler){

_next=newHandler;

}

protected:

BaseHandler* _next;

IEvent* _event;

};

http://www.slideshare.net/IgorShkulipa 33

Классы-обработчики

class Handler5: public BaseHandler {

public: Handler5() {

_event=new Event5(); _next=NULL;

}};

class Handler4: public BaseHandler {

public: Handler4() {

_event=new Event4(); _next=new Handler5();

}};

class Handler3: public BaseHandler {

public: Handler3() {

_event=new Event3(); _next=new Handler4();

}};

class Handler2: public BaseHandler {

public: Handler2() {

_event=new Event2(); _next=new Handler3();

}};

class Handler1: public BaseHandler {

public: Handler1() {

_event=new Event1(); _next= new Handler2();

}};

http://www.slideshare.net/IgorShkulipa 34

Класс тестового приложения

template<int iCount> class ChainApplication {

public:

ChainApplication(){_eventHandler=new

Handler1();}

~ChainApplication(){ delete _eventHandler;};

void Run() {

srand(time(0));

for (int i=0;i<iCount;i++)

{

HandleEvent(GenerateRandomEvent());

}}

private:

void HandleEvent(IEvent* ev)

{

_eventHandler->Handle(ev);

}

private:

BaseHandler* _eventHandler;

...

http://www.slideshare.net/IgorShkulipa 35

Класс тестового приложения...

private:

IEvent* GenerateRandomEvent()

{

int iEvent=rand() % 6;

IEvent* result;

switch (iEvent)

{

case 0: result= new Event1();break;

case 1: result= new Event2();break;

case 2: result= new Event3();break;

case 3: result= new Event4();break;

case 4: result= new Event5();break;

default: result= new Event6();

}

cout<<"\nGenerated event: "<<result->GetEventType() <<"\n";

return result;

}

};

http://www.slideshare.net/IgorShkulipa 36

Результат цепочки ответственностей

int main()

{

ChainApplication<5>* capp=

new ChainApplication<5>();

capp->Run();

}

Результат:Generated event: Event5

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Event5 successfully handled.

Generated event: Event4

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Event4 successfully handled.

Generated event: Event1

Event1 successfully handled.

Generated event: Event2

Sending event to next Handler...

Event2 successfully handled.

Generated event: Event6

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Unknown event. Can't handle.

http://www.slideshare.net/IgorShkulipa 37

Strategy

Паттерн Strategy предназначенный для определения семействаалгоритмов и инкапсуляции каждого из них и обеспечения ихвзаимозаменяемости.

Переносит в отдельную иерархию классов все детали, связанныес реализацией алгоритмов.

http://www.slideshare.net/IgorShkulipa 38

Пример

class IStrategy

{

public:

virtual void Use()=0;

protected:

void WakeUp() {cout<<"Wake up.\n";}

void Shower() {cout<<"Take shower.\n";}

void Dress() {cout<<"Dress.\n";}

void GoToBusStop() {cout<<"Go to bus stop.\n";}

void Wait() {cout<<"Wait.\n";}

void Arrive() {cout <<"Arrive.\n";};

void DoWork() {cout <<"Do work.\n";}

void DoExercises() {cout <<"Do exercises.\n";}

void Walk() {cout<<"Walk.\n";}

void GoOut() {cout<<"Go out.\n";}

void GoToPark() {cout<<"Go to park.\n";};

};

http://www.slideshare.net/IgorShkulipa 39

Классы конкретных стратегий

class GoToWorkStrategy: public IStrategy {

public:

virtual void Use() {

WakeUp(); Shower(); Dress(); GoOut();

GoToBusStop(); Wait(); Arrive(); DoWork();

}};

class GoWalkStrategy: public IStrategy {

public:

virtual void Use() {

GoOut(); GoToPark(); Walk();

}};

class GoToGymStrategy: public IStrategy {

public:

virtual void Use() {

GoOut(); GoToBusStop(); Arrive(); DoExercises();

}};

http://www.slideshare.net/IgorShkulipa 40

Клиент стратегий

class IStrategyClient

{

public:

virtual void UseStrategy()=0;

virtual void SetStrategy(IStrategy* st){_strategy=st;};

protected:

IStrategy* _strategy;

};

class StrategyClient1: public IStrategyClient

{

public:

StrategyClient1(){}

void UseStrategy()

{

_strategy->Use();

}

};

http://www.slideshare.net/IgorShkulipa 41

Использование стратегий

int main()

{

IStrategyClient* stClient=new StrategyClient1();

stClient->SetStrategy(new GoToWorkStrategy());

stClient->UseStrategy();

cout<<"\n";

stClient->SetStrategy(new GoToGymStrategy());

stClient->UseStrategy();

cout<<"\n";

stClient->SetStrategy(new GoWalkStrategy);

stClient->UseStrategy();

}

Результат:Wake up.

Take shower.

Dress.

Go out.

Go to bus stop.

Wait.

Arrive.

Do work.

Go out.

Go to bus stop.

Arrive.

Do exercises.

Go out.

Go to park.

Walk.

http://www.slideshare.net/IgorShkulipa 42

Паттерны для самостоятельного изучения

◦ Паттерн Iterator

◦ Паттерн Interpreter

◦ Паттерн Mediator

◦ Паттерн Memento

◦ Паттерн Observer

◦ Паттерн State

◦ Паттерн Template Method

◦ Паттерн Visitor

http://www.slideshare.net/IgorShkulipa 43

Лабораторная работа №17. Паттерны проектирования

Самостоятельно изучить теоретическую часть, а так жепридумать реализовать примеры для паттернов:

Структурные:

1. Composite

2. Decorator

3. Flyweight

4. Proxy

Поведенческие:

1. Iterator

2. Interpreter

3. Mediator

4. Memento

5. Observer

6. State

7. Template Method

8. Visitor

top related