Шаблони за дизайн - Бързо ръководство за модела на наблюдателя.

Моделът на наблюдателя е много често използван модел. Всъщност това е толкова често, че се стандартизира в много програмни езици / библиотеки. В Java той съществува injava.util.Observer (остарял в Java 9). В Python е толкова близо, колкото apip инсталирате модел-наблюдател. В C ++ понякога можем да използваме boost библиотека, по-точно #include . Въпреки това, той се използва широко в промишлеността като решение по поръчка. За да можем да го използваме правилно и да разберем сложността му, трябва да се потопим и да го изследваме.

Моделът на наблюдателя е класифициран сред моделите на поведенчески дизайн. Моделите на поведенчески дизайн са най-конкретно свързани с комуникацията между класове / обекти. [от дизайнерските модели обяснено просто]

Какво е модел за наблюдение? Освен ходещ монитор, който излъчва аналогова телевизия (както е на снимката). Целта на шаблона е да дефинира връзка „много към много“, така че когато един обект промени състоянието, останалите се известяват и актуализират автоматично. По-точно, той иска да бъде информиран за събития, случващи се в системата. Нека сложим парчетата от пъзела заедно в три стъпки.

Стъпка 1 - Ключови думи

Дефинирането на ключови думи е тайната рецепта в тази серия от бързи ръководства. Този метод ми помогна истински да разбера дизайнерските модели, да ги хардкодирам в съзнанието си и да проумея разликите между другите модели на дизайн.

  1. Предмет: Той се счита за съхраняващ информация, данни или бизнес логика.
  2. Регистрация / Прикачване: Наблюдателите се регистрират в темата, защото искат да бъдат уведомени, когато има промяна.
  3. Събитие: Събитията действат като спусък в темата, така че всички наблюдатели да бъдат уведомени.
  4. Уведомете: В зависимост от прилагането, субектът може да „избута“ информация към наблюдателите или, наблюдателите могат да „изтеглят“, ако се нуждаят от информация от темата.
  5. Актуализация: Наблюдателите актуализират състоянието си независимо от другите наблюдатели, но тяхното състояние може да се промени в зависимост от задействаното събитие.

Стъпка 2 - Диаграма

Нека разделим този дизайн на различни класове, за да опростим това малко.

  • ConcreteObservers са класове, които съдържат информация, специфична за текущия екземпляр. Функцията за актуализиране се извиква от операцията notify () на субекта. Наблюдателите се актуализират независимо въз основа на тяхното текущо състояние.
  • Наблюдателят е родителският клас на конкретните наблюдатели. Съдържа предметна инстанция. Когато наблюдател се инициализира, той се регистрира / прикрепя към обекта.
  • Класът Subject има списък или колекция от наблюдатели. Когато се задейства събитие, той извиква операцията notify (), която преглежда всички наблюдатели, като извиква тяхната функция за актуализиране.

Стъпка 3 - Код по пример

Бих предложил да копирате кодовия клас по клас от моето хранилище на git „Andreas Poyias“ или от фрагментите по-долу (в предвидения ред) и да го поставите във всеки от наличните онлайн C ++ редактори като c ++ shell, jdoodle, onlineGDB и стартирайте то да наблюдава изхода. След това прочетете коментарите или описанието по-долу. Отделете време, като го прочетете старателно (това означава една минута, не по-малко и не повече).

Пример: Помислете за футболна игра. Много привърженици гледат мача. Разделихме привържениците на две категории по възраст, млади и стари. Когато техният отбор вкара гол, привържениците реагират различно според възрастта и нивото на вълнение.
Сега, да поговорим с термини, използвани за модела на наблюдателите:

  • Играта е тема, а привържениците са наблюдатели.
  • Всички наблюдатели са прикачени / регистрирани към темата и те биват уведомявани, когато футболният им отбор вкара (спусъчното събитие е, ако техният отбор отбележи).
  • Наблюдателите актуализират поведението си в зависимост от полученото уведомление.

Предмет
За този клас се нуждаем от достъп до списък с наблюдатели. Когато наблюдателите са на път да се регистрират, те извикват функцията theattach (тази), за да се добавят към наличния списък (това е инстанция за наблюдател). Когато се задейства събитие, уведомете () всички наблюдатели независимо да актуализират състоянието си. В този пример спусъкът е, ако футболният отбор на наблюдателя вкара.

#include 
#include 
използване на stdpace пространство на имената;
Тема на клас {
    вектор  наблюдатели;
    bool вкара; // спусък, събитие
публичния:
    // регистрирайте наблюдатели
    невалиден прикачен файл (наблюдател * obs) {
        observers.push_back (изм);
    }
   
   // Това е СЪБИТИЕТО
   // задайте ако е отбелязан и уведомявайте ВСИЧКИ наблюдатели
   void setScored (bool Score) {
      вкара = Резултат;
      уведомява ();
   }
bool getScored () {
      възвратен резултат;
   }
   // внедряването на известия е по-надолу
   // така че скриптът да се компилира и изпълнява
   невалидно известяване ();
};

наблюдател
Този клас зависи от предмета, в който е регистриран. Когато конкретни наблюдатели се инициализират, те се прикрепят към субекта. В този пример състоянието на всеки наблюдател е неговото вълнение.

клас Наблюдател
{
    Тема * subj;
    int вълнениеLevel; // държава
  публичния:
    Наблюдател (Subject * mod, int excLevel)
    {
        subj = mod;
        excitementLevel = excLevel;
        // Наблюдателите се регистрират / прикачат към Темата
        subj-> прикачвате (това);
    }
    актуална актуализация на празнотата () = 0;
  защитени:
    Тема * getSubject () {
       връщане subj;
    }
    void setExcitementLevel (int excLevel) {
       excitementLevel = excLevel;
    }
    int getExcitementLevel () {
       връщане вълнениеLevel;
    }
};

Това е theSubject :: notify () декларацията и както споменахме преди нейната задача е да уведомява всички наблюдатели да актуализират състоянието си.

void Subject :: известие () {
  за (int i = 0; i  актуализация ();
}

Конкретни наблюдатели
Конкретните наблюдатели наследяват от класа Observer и всички те трябва да имат функцията за актуализиране. В този пример конкретните наблюдатели се разграничават между млади и стари привърженици. Ако нивото на вълнението им стане твърде високо, по-възрастните привърженици имат риск от инфаркт, а по-младите имат риск да пият и шофират. Състоянието им се актуализира независимо, както ще докажем в основната функция по-долу.

клас Old_ConcreteObserver: обществен наблюдател
{
   публичния:
     // Призовава родителски конструктор да се регистрира с обект
     Old_ConcreteObserver (Тема * mod, int div)
        : Наблюдател (мод, div) {}
     // За по-възрастни хора, ако нивото на вълнение
     // е над 150 те рискуват от сърдечен удар
     невалидна актуализация ()
     {
        bool score = getSubject () -> getScored ();
        setExcitementLevel (getExcitementLevel () + 1);
        ако (вкара && getExcitementLevel ()> 150)
        {
          cout << "Отборът на Old Observer отбеляза !!"
               << "Нивото на вълнението му е"
               << getExcitementLevel ()
               << "внимавайте от инфаркти!" << endl;
        } Друг {
          cout << "Екипът не вкара. Yeeeih няма за какво да се тревожим"
               << endl;
        }
    } // край на актуализацията ()
};
клас Young_ConcreteObserver: обществен наблюдател
{
   публичния:
     // Призовава родителски конструктор да се регистрира с обект
     Young_ConcreteObserver (Тема * mod, int div)
       : Наблюдател (мод, div) {}
     // За по-възрастни хора, ако нивото на вълнение
     // е над 100 те рискуват от сърдечен удар
     невалидна актуализация ()
     {
        bool score = getSubject () -> getScored ();
        setExcitementLevel (getExcitementLevel () + 1);
        ако (вкара && getExcitementLevel ()> 100)
        {
          cout << "Екипът на младия наблюдател вкара !!"
               << "Нивото на вълнението му е"
               << getExcitementLevel ()
               << "не пия и не шофирай !!" << endl;
        } Друг {
          cout << "Екипът не вкара. Yeeh няма за какво да се тревожим"
               << endl;
       }
    } // край на актуализацията ()
};

Главна функция
Конкретните наблюдатели се регистрират в инстанцията на субекта. Състоянието им е нивото на вълнение, което е вторият параметър. Когато събитието се задейства „subj.setScored (true)“, тогава се призоваваSubject :: notify () да актуализира регистрираните наблюдатели. В сценария по-долу имаме трима наблюдатели, младият Obs1 е превъзбуден и рискува да пие и шофира, старият Obs1 също е превъзбуден. И накрая, youngObs2, който също е млад като първия, няма от какво да се притеснява, тъй като не е превъзбуден.

Важно е да се отбележи, че тримата наблюдатели се актуализират независимо въз основа на състоянието си (ниво на вълнение) и вида им (млади или стари).
int main () {
   Тема subj;
   Young_ConcreteObserver youngObs1 (& subj, 100);
   Old_ConcreteObserver oldObs1 (& subj, 150);
   Young_ConcreteObserver youngObs2 (& subj, 52);
   subj.setScored (истина);
}
// Изход
// Отборът на младия наблюдател вкара !! Нивото на вълнението му е 101
// не пия и шофирай !!
// Отборът на Old Observer вкара !! Нивото на вълнението му е 151 часовника
// извън сърдечни пристъпи! Отборът не вкара.
// Yeeh няма за какво да се тревожиш

Има няколко предимства за използването на модел Observer и няколко точки, които трябва да се отбележат, когато този модел трябва да бъде приближен [Learning Python Design Patterns].

  • Моделът на наблюдателя осигурява дизайн, при който субектът и наблюдателят са слабо свързани. Темата не е необходимо да знае за класа ConcreteObserver. Всеки нов наблюдател може да бъде добавен по всяко време. Не е необходимо да променяте Subject, когато се добави нов наблюдател. Наблюдателите и субектите не са обвързани и са независими един от друг, следователно промените в Темата или Наблюдателя няма да се повлияят един на друг.
  • Няма вариант за композиция, тъй като интерфейсът на наблюдателя може да бъде инстанциран.
  • Ако Наблюдателят бъде злоупотребен, той лесно може да добави сложност и да доведе до проблеми с производителността.
  • Известията могат да бъдат ненадеждни и могат да доведат до състезателни условия или несъответствие.

Следващият блог ще бъде бързо ръководство за модела на дизайна на Bridge. Това е структурен дизайн, който се използва доста в индустрията. Не забравяйте да харесате / плеснете в моя блог и следвайте моя акаунт. Това е, за да ми даде удовлетворението, че помогнах на някои колеги разработчици и ме накара да продължа да пиша. Ако има конкретен модел на дизайн, за който бихте искали да научите, уведомете ме, за да мога да го предоставя за вас в бъдеще.

Други бързи указания за моделите на дизайн:

  1. Шаблони за дизайн - Бързо ръководство за абстрактна фабрика.
  2. Шаблони за дизайн - Бързо ръководство за мост на мост.
  3. Шаблони за дизайн - Бързо ръководство за модел на строителя.
  4. Шаблони за дизайн - Бързо ръководство за Декоратора Модел.
  5. Шаблони за дизайн - Бързо ръководство за фасаден модел.
  6. Шаблони за дизайн - Бързо ръководство за модел на наблюдателя.
  7. Шаблони за дизайн - Бързо ръководство за Singleton Pattern.