- •Лабораторная работа №4 Шаблоны проектирования
- •Теоретические сведения
- •Отношения между классами. На диаграммах классов языка uml
- •Суть паттерна
- •Решение
- •Адаптер объектов
- •Адаптер классов
- •Адаптер классов не нуждается во вложенном объекте, так как он может одновременно наследовать и часть существующего класса, и часть сервиса.
- •Фасад (Facade)
- •Концептуальный пример
- •Program.Cs:
- •Output.Txt: Результат выполнения
- •Изолирует клиентов от компонентов подсистемы Уменьшая тем самым число объектов, с которыми клиентам приходится иметь дело, упрощая работу с подсистемой.
- •Позволяет ослабить связанность между подсистемой и ее клиентами.
- •Фасад не исключает возможности приложениям напрямую обращаться к классам подсистемы, если это необходимо.
- •Заместитель (Proxy)
- •3. Локальный запуск сервиса (удалённый прокси). Когда настоящий сервисный объект находится на удалённом сервере.
- •Концептуальный пример
- •Декоратор (Decorator)
- •// Объект
- •} //Ptr2 выходит из области видимости, но объект не //освобождается, потому что есть ptr, который по-прежнему //ссылается на него } //ptr выходит из области видимости, и объект уничтожается
- •Пример на языке c#
- •Порождающие шаблоны Абстрактная фабрика (Abstract Factory)
- •1. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы.
- •3. Таким образом, еще раз - предоставляет интерфейс для создания семейств, связанных между собой, или зависимых объектов.
- •Клиент пользуется только интерфейсами, заданными в классах «Абстрактная фабрика» и «Абстрактный продукт».
- •Фабричный метод (Factory Method)
- •Void info() {
- •Void info() {
- •Void info() {
- •Int main()
- •Одиночка (Singleton) Суть паттерна
- •If(!p_instance)
- •Поведенческие шаблоны Стратегия (Strategy)
- •Стратегии построения пути.
- •Структура
- •Концептуальный пример
- •Program.Cs: Пример структуры паттерна
- •Output.Txt: Результат выполнения
- •Void useStrategy(void)
- •Void setStrategy(Strategy* o)
- •Int main(int /*argc*/, char* /*argv*/[])
- •Наблюдатель (Observer) Суть паттерна
- •Решение
- •Структура
- •Шаги реализации
- •Концептуальный пример
- •Program.Cs: Пример структуры паттерна
- •// Random.Next(…) - Метод, возвращает случайное целое число //в указанном диапазоне.
- •Output.Txt: Результат выполнения
- •Использование паттерна Observer
- •Команда (Command)
- •Структура
- •Output.Txt: Результат выполнения
- •Задания для лабораторной работы
Использование паттерна Observer
Проведите различия между основной (или независимой) и дополнительной (или зависимой) функциональностями.
Смоделируйте "независимую" функциональность с помощью абстракции "Субъект".
Смоделируйте "зависимую" функциональность с помощью иерархии "Наблюдатель".
Класс Subject связан только c базовым классом Observer.
Клиент настраивает количество и типы Наблюдателей.
Наблюдатели регистрируются у Субъекта.
Субъект извещает всех зарегистрированных Наблюдателей.
Субъект может "протолкнуть" информацию в Наблюдателей, или Наблюдатели могут "вытянуть" необходимую им информацию от объекта Subject.
#include <iostream> #include <vector> using namespace std; // "Независимая" функциональность class Subject { // Связь только с базовым классом Observer vector < class Observer * > views; int value; public: void attach(Observer *obs) { //прицепить наблюдателя views.push_back(obs); } void setVal(int val) { value = val; notify(); } int getVal() { return value; } void notify(); };
// "Зависимая" функциональность class Observer { Subject *model; int denom; //категория, наименование public: Observer(Subject *mod, int div) { model = mod; denom = div; // Наблюдатели регистрируются у субъекта (Subject) model->attach(this); } virtual void update() = 0; protected: Subject *getSubject() { return model; } int getDivisor() { return denom; } };
void Subject::notify() { // Извещение наблюдателей for (int i = 0; i < views.size(); i++) views[i]->update(); }
class DivObserver: public Observer { public: DivObserver(Subject *mod, int div): Observer(mod, div){} void update() { // "Вытягивание" интересующей информации int v = getSubject()->getVal(), d = getDivisor(); cout << v << " div " << d << " is " << v/d << '\n'; } }; class ModObserver: public Observer { public: ModObserver(Subject *mod, int div): Observer(mod, div){} void update() { int v = getSubject()->getVal(), d = getDivisor(); cout << v << " mod " << d << " is " << v%d << '\n'; } }; int main() { Subject subj; DivObserver divObs1(&subj, 4); // Клиент настраивает число DivObserver divObs2(&subj, 3); // и типы наблюдателей ModObserver modObs3(&subj, 3); subj.setVal(14); } |
Вывод программы:
|
14 div 4 is 3 14 div 3 is 4 14 mod 3 is 2 |
//==================================================
#include <iostream>
#include <string>
#include <list>
using namespace std;
class SupervisedString;
class IObserver
{
public:
virtual void handleEvent(const SupervisedString&) = 0;
};
class SupervisedString // Observable class
{
string _str;
list<IObserver* const> _observers;
void _Notify()
{
for(auto iter : _observers)
{
iter->handleEvent(*this);
}
}
public:
void add(IObserver& ref)
{
_observers.push_back(&ref);
}
void remove(IObserver& ref)
{
_observers.remove(&ref);
}
const string& get() const
{
return _str;
}
void reset(string str)
{
_str = str;
_Notify();
}
};
class Reflector: public IObserver // Prints the observed string into cout
{
public:
virtual void handleEvent(const SupervisedString& ref)
{
cout << ref.get() << endl;
}
};
class Counter: public IObserver
// Prints the length of observed string into cout
{
public:
virtual void handleEvent(const SupervisedString& ref)
{
cout << "length = " << ref.get().length() << endl;
}
};
int main()
{
SupervisedString str;
Reflector refl;
Counter cnt;
str.add(refl);
str.reset("Hello, World!");
cout << endl;
str.remove(refl);
str.add(cnt);
str.reset("World, Hello!");
cout << endl;
return 0;
}
Смысл данного паттерна заключается в том, что если объект обновляется, то все его зависимые объекты обновляются так же.
Применение
Если система обладает следующими свойствами:
существует как минимум один объект, который рассылает сообщения;
имеется более одного получателя сообщения и их количество может меняться в процессе работы системы;
объекты не сильно связываются;
стоит так же заметить, что паттерн часто применяют в ситуациях, когда отправителю не важно, что будут делать получатели с полученным сообщением;
Диаграмма классов представлена ниже.
Основными элементами в данном паттерне являются объект наблюдения (Subject) и реализация различных наблюдателей (extends Observer).
Будем хранить всех наблюдателей объекта непосредственно в нем.
Реализуем паттерн Наблюдатель, в основу идеи положим оповещение учителя и родителей (Наблюдателей) о полученной учеником (Subject) оценке.
Абстрактный класс Observer содержит абстрактный метод update, который реализует каждый из конкретных наблюдателей в зависимости от своих целей.
Так же класс Observer содержит ссылку на субъект, за которым он наблюдает.
Реализация представлена ниже:
public abstract class Observer {
protected Subject object;
public abstract void update();
}
Тут все довольно просто и нет необходимости пояснять.
Далее реализуем классы учителя и родителя соответственно.
public class Teacher extends Observer {
public Teacher(Subject object){
this.object = object;
this.object.attach(this);
}
@Override
public void update() {
System.out.println("Teacher is aware of your results :" + this.object.getState());
}
}
И класс родителей наблюдателей:
public class Parents extends Observer{
public Parents(Subject object){
this.object = object;
this.object.attach(this);
}
@Override
public void update() {
System.out.println("Parents are aware of your results :" + this.object.getState());
}
}
Классы Teacher и Parents практически одинаковы.
Тут стоит заметить, что экземпляр данного класса позволяет следить за 1 объектом и привязка осуществляется в конструкторе с помощью метода attach.
Когда ученик получит новую оценка учитель и родители непременно об этом узнают.
А теперь рассмотрим реализация самого субъекта.
public class Subject {
private List<Observer> observers = new ArrayList<Observer>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
public void attach(Observer observer){
observers.add(observer);
}
private void notifyAllObservers(){
for (Observer observer: observers){
observer.update();
}
}
}
Объект наблюдения содержит список всех наблюдателей и в случае изменения состояния, все они будут оповещены.
Можно было бы написать код, который позволял бы удалять смотрителей, но мы просто рассмотрели саму идею.
Все основные классs записаны и теперь остается только это все запустить, класс ниже, позволит это сделать.
public class ObserverRunner {
public static void main(String args[]){
Subject pupil = new Subject();
new Parents(pupil);
new Teacher(pupil);
System.out.println("You've received new mark: 5");
pupil.setState(5);
}
}
Вы можете запустить данный пример и посмотреть, что любые полученные оценки у ученика не остаются без внимания.
