Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лабы / Лабораторная_работа_по_паттернам23.docx
Скачиваний:
0
Добавлен:
11.02.2026
Размер:
1.18 Mб
Скачать

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

  1. Проведите различия между основной (или независимой) и дополнительной (или зависимой) функциональностями.

  2. Смоделируйте "независимую" функциональность с помощью абстракции "Субъект".

  3. Смоделируйте "зависимую" функциональность с помощью иерархии "Наблюдатель".

  4. Класс Subject связан только c базовым классом Observer.

  5. Клиент настраивает количество и типы Наблюдателей.

  6. Наблюдатели регистрируются у Субъекта.

  7. Субъект извещает всех зарегистрированных Наблюдателей.

  8. Субъект может "протолкнуть" информацию в Наблюдателей, или Наблюдатели могут "вытянуть" необходимую им информацию от объекта 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);

     }

}

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