Patrón de observador para sensores de temperatura y presión -- ++ campo con observer-pattern camp codereview Relacionados El problema

Observer pattern for temperature and pressure sensors


1
vote

problema

Español

He intentado implementar el patrón de observador. El código debe poder manejar un número variable de observables (ajuste el tiempo de compilación) y notifique a cualquier número de observadores / registrables. Cualquier observable es adecuado debido al uso de plantillas. Los observadores / Registradores (?) Deben derivarse de la base de cregisterable. Por lo tanto, polimorfismo.

En una revisión reciente, he aprendido sobre los punteros inteligentes y la regla de tres ... pero usar un STD :: Shared_PTR resultó ser bastante difícil para este caso de uso. Intenté ser a la defensiva varias veces implementando un operador privado = métodos y constructores de copias privadas. Buena idea?

compilando

  g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/CAnotherPressureRegisterable.cpp -o obj/Debug/CAnotherPressureRegisterable.o g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/CAnotherTemperatureRegisterable.cpp -o obj/Debug/CAnotherTemperatureRegisterable.o g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/CCombiRegister.cpp -o obj/Debug/CCombiRegister.o g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/CPressureRegisterable.cpp -o obj/Debug/CPressureRegisterable.o g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/CTemperatureRegisterable.cpp -o obj/Debug/CTemperatureRegisterable.o g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/main.cpp -o obj/Debug/main.o g++  -o bin/Debug/ObserverPattern obj/Debug/CAnotherPressureRegisterable.o obj/Debug/CAnotherTemperatureRegisterable.o obj/Debug/CCombiRegister.o obj/Debug/CPressureRegisterable.o obj/Debug/CTemperatureRegisterable.o obj/Debug/main.o      

Canotherpressurreegisterable.cpp

      #include <stdio.h>      #include "CAnotherPressureRegisterable.h"      void CAnotherPressureRegisterable::Notify(TPressure& aPressure)     {       printf("CAnotherPressureRegisterable::Notify(...): Received aPressure.iPressureData= %i ",              aPressure.iPressureData);     }      CAnotherPressureRegisterable::~CAnotherPressureRegisterable()     {       printf("CAnotherPressureRegisterable::~CAnotherPressureRegisterable(): Started. ");     }      CAnotherPressureRegisterable CAnotherPressureRegisterable::operator=(const CAnotherPressureRegisterable& aAnotherPressureRegisterable)     {       printf("CAnotherPressureRegisterable::operator=(...): Do not copy an instance of this class. ");       CAnotherPressureRegisterable myAnotherPressureRegisterable;       return myAnotherPressureRegisterable;     }   

Canotherpressurreegisterable.h

      #ifndef CANOTHERPRESSUREREGISTERABLE_H     #define CANOTHERPRESSUREREGISTERABLE_H      #include "TPressure.h"     #include "CSubject.h"      class CAnotherPressureRegisterable : public CRegisterableBase<TPressure>     {     public:       void Notify(TPressure& aPressure);        ~CAnotherPressureRegisterable();      private:       CAnotherPressureRegisterable operator=(const CAnotherPressureRegisterable& aAnotherPressureRegisterable);     };      #endif // CANOTHERPRESSUREREGISTERABLE_H   

canothertemperatureegisterable.cpp

      #include <stdio.h>      #include "CAnotherTemperatureRegisterable.h"      void CAnotherTemperatureRegisterable::Notify(TTemperature& aTemperature)     {       printf("CAnotherTemperatureRegisterable::Notify(...): Received aTemperature.iTemperatureData= %i ",              aTemperature.iTemperatureData);     }      CAnotherTemperatureRegisterable::~CAnotherTemperatureRegisterable()     {       printf("CAnotherTemperatureRegisterable::~CAnotherTemperatureRegisterable(): Started. ");     }      CAnotherTemperatureRegisterable CAnotherTemperatureRegisterable::operator=(const CAnotherTemperatureRegisterable& aAnotherPressureRegisterable)     {       printf("CAnotherTemperatureRegisterable::operator=(...): Do not copy an instance of this class. ");       CAnotherTemperatureRegisterable myAnotherTemperatureRegisterable;       return myAnotherTemperatureRegisterable;     }   

CanothertemperatureRegisterable.h

      #ifndef CANOTHERTEMPERATUREREGISTERABLE_H     #define CANOTHERTEMPERATUREREGISTERABLE_H      #include "TTemperature.h"     #include "CSubject.h"      class CAnotherTemperatureRegisterable : public CRegisterableBase<TTemperature>     {     public:       void Notify(TTemperature& aTemperature);        ~CAnotherTemperatureRegisterable();      private:       CAnotherTemperatureRegisterable operator=(const CAnotherTemperatureRegisterable& aAnotherPressureRegisterable);     };       #endif // CANOTHERTEMPERATUREREGISTERABLE_H   

ccombireegister.cpp

      #include <stdio.h>      #include "CCombiRegister.h"      CCombiRegister::CCombiRegister(CSubject<TTemperature>* aTemperatureSubjectPtr,                                    CSubject<TPressure>* aPressureSubjectPtr)       : iTemperatureSubjectPtr(aTemperatureSubjectPtr),         iPressureSubjectPtr(aPressureSubjectPtr)     {       printf("CRegisterPressureAndTemperature::CRegisterPressureAndTemperature(): Started. ");       iTemperatureRegisterablePtr = new CAnotherTemperatureRegisterable();       iPressureRegisterablePtr    = new CAnotherPressureRegisterable();       printf("CRegisterPressureAndTemperature::CRegisterPressureAndTemperature(): Finished. ");     }      CCombiRegister::CCombiRegister(CCombiRegister& aRegisterPressureAndTemperature)     {     }      CCombiRegister::~CCombiRegister()     {       iTemperatureSubjectPtr->Unregister(iTemperatureRegisterablePtr);       iPressureSubjectPtr->Unregister(iPressureRegisterablePtr);        delete iTemperatureRegisterablePtr;       delete iPressureRegisterablePtr;     }      void CCombiRegister::RegisterTemperature(CSubject<TTemperature>& aSubject)     {       printf("CRegisterPressureAndTemperature::RegisterTemperature(...): Started. ");       aSubject.Register(iTemperatureRegisterablePtr);       printf("CRegisterPressureAndTemperature::RegisterTemperature(...): Finished. ");     }      void CCombiRegister::RegisterPressure(CSubject<TPressure>& aSubject)     {       printf("CRegisterPressureAndTemperature::RegisterPressure(...): Started. ");       aSubject.Register(iPressureRegisterablePtr);       printf("CRegisterPressureAndTemperature::RegisterPressure(...): Finished. ");     }   

ccombireegister.h

      #ifndef CCOMBIREGISTER_H     #define CCOMBIREGISTER_H      #include "TTemperature.h"     #include "TPressure.h"      #include "CSubject.h"      #include "CAnotherTemperatureRegisterable.h"     #include "CAnotherPressureRegisterable.h"      class CCombiRegister     {     public:       CCombiRegister(CSubject<TTemperature>* aTemperatureSubjectPtr, CSubject<TPressure>* aPressureSubjectPtr);       ~CCombiRegister();        void RegisterTemperature(CSubject<TTemperature>& aSubject);       void RegisterPressure(CSubject<TPressure>& aSubject);      private:       CCombiRegister(CCombiRegister& aRegisterPressureAndTemperature);        CAnotherTemperatureRegisterable* iTemperatureRegisterablePtr;       CAnotherPressureRegisterable* iPressureRegisterablePtr;        CSubject<TTemperature>* iTemperatureSubjectPtr;       CSubject<TPressure>* iPressureSubjectPtr;       // I tried to implement a smart pointer here. FAIL     };      #endif // CCOMBIREGISTER_H   

CPressurreegisterable.cpp

  n0  

CPressurreegisterable.h

  n1  

CSubject.H

  n2  

ctemperatureegisterable.cpp

  n3  

ctemperatureegisterable.h

  n4  

TPressure.H

  n5  

ttemperature.h

  n6  

main.cpp

  n7  
Original en ingles

I have tried to implement the observer pattern. The code should be able to handle a variable number of observables (set compile time) and notify any number of observers/registerables. Any observable is suitable because of the use of templates. The observers/registerers (?) must be derived from CRegisterableBase. Hence, polymorphism.

In a recent review I have learned about smart pointers and the Rule of Three... but using a std::shared_ptr turned out to be quite hard for this use case. I tried to be defensive a few times by implementing private operator= methods and private copy constructors. Good idea?

Compiling

g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/CAnotherPressureRegisterable.cpp -o obj/Debug/CAnotherPressureRegisterable.o g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/CAnotherTemperatureRegisterable.cpp -o obj/Debug/CAnotherTemperatureRegisterable.o g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/CCombiRegister.cpp -o obj/Debug/CCombiRegister.o g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/CPressureRegisterable.cpp -o obj/Debug/CPressureRegisterable.o g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/CTemperatureRegisterable.cpp -o obj/Debug/CTemperatureRegisterable.o g++ -Wall -g -std=c++11  -c /mnt/home/Data_MaOt/Short_C_and_Cpp_progs/DesignPatterns/ObserverPattern/main.cpp -o obj/Debug/main.o g++  -o bin/Debug/ObserverPattern obj/Debug/CAnotherPressureRegisterable.o obj/Debug/CAnotherTemperatureRegisterable.o obj/Debug/CCombiRegister.o obj/Debug/CPressureRegisterable.o obj/Debug/CTemperatureRegisterable.o obj/Debug/main.o    

CAnotherPressureRegisterable.cpp

    #include <stdio.h>      #include "CAnotherPressureRegisterable.h"      void CAnotherPressureRegisterable::Notify(TPressure& aPressure)     {       printf("CAnotherPressureRegisterable::Notify(...): Received aPressure.iPressureData= %i\n",              aPressure.iPressureData);     }      CAnotherPressureRegisterable::~CAnotherPressureRegisterable()     {       printf("CAnotherPressureRegisterable::~CAnotherPressureRegisterable(): Started.\n");     }      CAnotherPressureRegisterable CAnotherPressureRegisterable::operator=(const CAnotherPressureRegisterable& aAnotherPressureRegisterable)     {       printf("CAnotherPressureRegisterable::operator=(...): Do not copy an instance of this class.\n");       CAnotherPressureRegisterable myAnotherPressureRegisterable;       return myAnotherPressureRegisterable;     } 

CAnotherPressureRegisterable.h

    #ifndef CANOTHERPRESSUREREGISTERABLE_H     #define CANOTHERPRESSUREREGISTERABLE_H      #include "TPressure.h"     #include "CSubject.h"      class CAnotherPressureRegisterable : public CRegisterableBase<TPressure>     {     public:       void Notify(TPressure& aPressure);        ~CAnotherPressureRegisterable();      private:       CAnotherPressureRegisterable operator=(const CAnotherPressureRegisterable& aAnotherPressureRegisterable);     };      #endif // CANOTHERPRESSUREREGISTERABLE_H 

CAnotherTemperatureRegisterable.cpp

    #include <stdio.h>      #include "CAnotherTemperatureRegisterable.h"      void CAnotherTemperatureRegisterable::Notify(TTemperature& aTemperature)     {       printf("CAnotherTemperatureRegisterable::Notify(...): Received aTemperature.iTemperatureData= %i\n",              aTemperature.iTemperatureData);     }      CAnotherTemperatureRegisterable::~CAnotherTemperatureRegisterable()     {       printf("CAnotherTemperatureRegisterable::~CAnotherTemperatureRegisterable(): Started.\n");     }      CAnotherTemperatureRegisterable CAnotherTemperatureRegisterable::operator=(const CAnotherTemperatureRegisterable& aAnotherPressureRegisterable)     {       printf("CAnotherTemperatureRegisterable::operator=(...): Do not copy an instance of this class.\n");       CAnotherTemperatureRegisterable myAnotherTemperatureRegisterable;       return myAnotherTemperatureRegisterable;     } 

CAnotherTemperatureRegisterable.h

    #ifndef CANOTHERTEMPERATUREREGISTERABLE_H     #define CANOTHERTEMPERATUREREGISTERABLE_H      #include "TTemperature.h"     #include "CSubject.h"      class CAnotherTemperatureRegisterable : public CRegisterableBase<TTemperature>     {     public:       void Notify(TTemperature& aTemperature);        ~CAnotherTemperatureRegisterable();      private:       CAnotherTemperatureRegisterable operator=(const CAnotherTemperatureRegisterable& aAnotherPressureRegisterable);     };       #endif // CANOTHERTEMPERATUREREGISTERABLE_H 

CCombiRegister.cpp

    #include <stdio.h>      #include "CCombiRegister.h"      CCombiRegister::CCombiRegister(CSubject<TTemperature>* aTemperatureSubjectPtr,                                    CSubject<TPressure>* aPressureSubjectPtr)       : iTemperatureSubjectPtr(aTemperatureSubjectPtr),         iPressureSubjectPtr(aPressureSubjectPtr)     {       printf("CRegisterPressureAndTemperature::CRegisterPressureAndTemperature(): Started.\n");       iTemperatureRegisterablePtr = new CAnotherTemperatureRegisterable();       iPressureRegisterablePtr    = new CAnotherPressureRegisterable();       printf("CRegisterPressureAndTemperature::CRegisterPressureAndTemperature(): Finished.\n");     }      CCombiRegister::CCombiRegister(CCombiRegister& aRegisterPressureAndTemperature)     {     }      CCombiRegister::~CCombiRegister()     {       iTemperatureSubjectPtr->Unregister(iTemperatureRegisterablePtr);       iPressureSubjectPtr->Unregister(iPressureRegisterablePtr);        delete iTemperatureRegisterablePtr;       delete iPressureRegisterablePtr;     }      void CCombiRegister::RegisterTemperature(CSubject<TTemperature>& aSubject)     {       printf("CRegisterPressureAndTemperature::RegisterTemperature(...): Started.\n");       aSubject.Register(iTemperatureRegisterablePtr);       printf("CRegisterPressureAndTemperature::RegisterTemperature(...): Finished.\n");     }      void CCombiRegister::RegisterPressure(CSubject<TPressure>& aSubject)     {       printf("CRegisterPressureAndTemperature::RegisterPressure(...): Started.\n");       aSubject.Register(iPressureRegisterablePtr);       printf("CRegisterPressureAndTemperature::RegisterPressure(...): Finished.\n");     } 

CCombiRegister.h

    #ifndef CCOMBIREGISTER_H     #define CCOMBIREGISTER_H      #include "TTemperature.h"     #include "TPressure.h"      #include "CSubject.h"      #include "CAnotherTemperatureRegisterable.h"     #include "CAnotherPressureRegisterable.h"      class CCombiRegister     {     public:       CCombiRegister(CSubject<TTemperature>* aTemperatureSubjectPtr, CSubject<TPressure>* aPressureSubjectPtr);       ~CCombiRegister();        void RegisterTemperature(CSubject<TTemperature>& aSubject);       void RegisterPressure(CSubject<TPressure>& aSubject);      private:       CCombiRegister(CCombiRegister& aRegisterPressureAndTemperature);        CAnotherTemperatureRegisterable* iTemperatureRegisterablePtr;       CAnotherPressureRegisterable* iPressureRegisterablePtr;        CSubject<TTemperature>* iTemperatureSubjectPtr;       CSubject<TPressure>* iPressureSubjectPtr;       // I tried to implement a smart pointer here. FAIL     };      #endif // CCOMBIREGISTER_H 

CPressureRegisterable.cpp

    #include <stdio.h>      #include "CPressureRegisterable.h"      void CPressureRegisterable::Notify(TPressure& aPressure)     {       printf("CPressureRegisterable::Notify(...): Received aPressure.iPressureData= %i\n",              aPressure.iPressureData);     }     CPressureRegisterable::~CPressureRegisterable()     {       printf("CPressureRegisterable::~CPressureRegisterable(): Started.\n");     }      CPressureRegisterable CPressureRegisterable::operator=(const CPressureRegisterable& aPressureRegisterable)     {       printf("CPressureRegisterable::operator=(...): Do not copy an instance of this class.\n");       CPressureRegisterable myPressureRegisterable;       return myPressureRegisterable;     } 

CPressureRegisterable.h

    #ifndef CPRESSUREREGISTERABLE_H     #define CPRESSUREREGISTERABLE_H      #include "TPressure.h"     #include "CSubject.h"      class CPressureRegisterable : public CRegisterableBase<TPressure>     {     public:       void Notify(TPressure& aPressure);        ~CPressureRegisterable();      private:       CPressureRegisterable operator=(const CPressureRegisterable& aPressureRegisterable);     };      #endif // CPRESSUREREGISTERABLE_H 

CSubject.h

    #ifndef CSUBJECT_H     #define CSUBJECT_H      #include <algorithm>    // std::find     #include <vector>       // std::vector      template <typename TypenameObservable>     class CRegisterableBase     {     public:       virtual void Notify(TypenameObservable& aTypenameObservable) = 0;       virtual ~CRegisterableBase() {};     };      template <typename TypenameObservable>     class CSubject     {     public:       void Register(CRegisterableBase<TypenameObservable>* aRegisterablePtr)       {         printf("CSubject::Register(): Started.\n");         typename std::vector<CRegisterableBase<TypenameObservable>*>::iterator it;         it = std::find(iRegisteredVector.begin(), iRegisteredVector.end(), aRegisterablePtr);          if (it == iRegisteredVector.end())         {           iRegisteredVector.push_back(aRegisterablePtr);         }         else         {           printf("CSubject::Register(): This registerable was already added.\n");         }          printf("CSubject::Register(): Finished.\n");       }        /////////////////////////////////////////////////////////////////////////////////////////////        void Unregister(CRegisterableBase<TypenameObservable>* aRegisterablePtr)       {         printf("CSubject::Unregister(): Started.\n");          typename std::vector<CRegisterableBase<TypenameObservable>*>::iterator it;         it = std::find(iRegisteredVector.begin(), iRegisteredVector.end(), aRegisterablePtr);          if (it != iRegisteredVector.end())         {           iRegisteredVector.erase(it);         }         else         {           printf("CSubject::Unregister(): This registerable was not added.\n");         }           printf("CSubject::Unregister(): Finished.\n");       }        /////////////////////////////////////////////////////////////////////////////////////////////        void NotifyObservers(TypenameObservable& aObservable)       {         printf("CSubject::NotifyObservers(): Started.\n");          for(typename std::vector<CRegisterableBase<TypenameObservable>*>::iterator it = iRegisteredVector.begin(); it < iRegisteredVector.end(); it++)         {           (*it)->Notify(aObservable);         }          printf("CSubject::NotifyObservers(): Finished.\n");       }      private:       std::vector<CRegisterableBase<TypenameObservable>*> iRegisteredVector;     };      #endif // CSUBJECT_H 

CTemperatureRegisterable.cpp

    #include "TTemperature.h"     #include "CSubject.h"     #include "CTemperatureRegisterable.h"      void CTemperatureRegisterable::Notify(TTemperature& aTemperature)     {       printf("CTemperatureRegisterable::Notify(...): Received aTemperature.iTemperatureData= %i\n",              aTemperature.iTemperatureData);     }      CTemperatureRegisterable::~CTemperatureRegisterable()     {       printf("CTemperatureRegisterable::~CTemperatureRegisterable(): Started.\n");     }      CTemperatureRegisterable CTemperatureRegisterable::operator=(const CTemperatureRegisterable& aTemperatureRegisterable)     {       printf("CTemperatureRegisterable::operator=(...): Do not copy an instance of this class.\n");       CTemperatureRegisterable myTemperatureRegisterable;       return myTemperatureRegisterable;     } 

CTemperatureRegisterable.h

    #ifndef CTEMPERATUREREGISTERABLE_H     #define CTEMPERATUREREGISTERABLE_H      #include "TTemperature.h"     #include "CSubject.h"      class CTemperatureRegisterable : public CRegisterableBase<TTemperature>     {     public:       void Notify(TTemperature& aTemperature);        ~CTemperatureRegisterable();      private:       CTemperatureRegisterable operator=(const CTemperatureRegisterable& aTemperatureRegisterable);     };      #endif // CTEMPERATUREREGISTERABLE_H 

TPressure.h

    #ifndef TPRESSURE_H     #define TPRESSURE_H      typedef struct     {       int iPressureData;     } TPressure;      #endif // TPRESSURE_H 

TTemperature.h

    #ifndef TTEMPERATURE_H     #define TTEMPERATURE_H      typedef struct     {       int iTemperatureData;     } TTemperature;      #endif // TTEMPERATURE_H 

main.cpp

    #include <stdio.h>      #include "TTemperature.h"     #include "TPressure.h"      #include "CTemperatureRegisterable.h"     #include "CPressureRegisterable.h"     #include "CCombiRegister.h"      #include "CSubject.h"      int main()     {       TTemperature t1 = {101};       TTemperature t2 = {102};       TTemperature t3 = {103};        TPressure p1 = {201};       TPressure p2 = {202};       TPressure p3 = {203};        CSubject<TTemperature> temperatureSubject;       CSubject<TPressure> pressureSubject;        CTemperatureRegisterable temperatureClient1;       CTemperatureRegisterable temperatureClient2;        temperatureSubject.Register(static_cast<CRegisterableBase<TTemperature>*> (&temperatureClient1));       temperatureSubject.Register(&temperatureClient2);        temperatureSubject.NotifyObservers(t1);       temperatureSubject.NotifyObservers(t2);        temperatureSubject.Unregister(&temperatureClient1);        temperatureSubject.NotifyObservers(t1);        CPressureRegisterable pressureClient1;       CPressureRegisterable pressureClient2;        pressureSubject.Register(&pressureClient1);       pressureSubject.Register(&pressureClient2);        pressureSubject.NotifyObservers(p1);       pressureSubject.NotifyObservers(p2);        pressureSubject.Unregister(&pressureClient1);        pressureSubject.NotifyObservers(p1);       pressureSubject.NotifyObservers(p2);        CCombiRegister myRegCombi(&temperatureSubject, &pressureSubject);        myRegCombi.RegisterTemperature(temperatureSubject);       myRegCombi.RegisterPressure(pressureSubject);        temperatureSubject.NotifyObservers(t3);       pressureSubject.NotifyObservers(p3);        return 0;     } 
     
     
     

Lista de respuestas

2
 
vote

La forma en que usa los punteros es bastante peligrosa y C ++ tiene herramientas para hacer esto totalmente seguro. El mayor problema de su implementación es el uso de posiblemente punteros colgantes en sus clases de sujetos. Pero también sus punteros en las interfaces están totalmente sin vigilancia contra nullptr s. Simplemente no pase los punteros a través de las funciones si no tiene que: Pasarlas como referencias.

Hay múltiples formas de abordar los problemas de por vida que su código podría potencialmente enfrentar:

  • sujetos propios a sus observadores de alguna manera (por valor o puntero compartido o lo que sea). De esa manera, los observadores nunca se acercan, por definición.

  • Los observadores cancelan su presentación a sus sujetos en sus destructores. Eso es una forma realmente sucia, ya que supera el propósito del patrón. En ese escenario, no solo los sujetos manejan observadores, sino que tiene algún ejemplo global que conoce todas las conexiones entre sujetos u observadores, sabe a qué temas se han registrado. Eh ... no.

  • Los sujetos tienen solo referencias débiles en forma de std::weak_ptr a sus observadores. Una referencia débil puede decir si un observador aún vive y se puede construir a partir de un 9988776655544332 .

Creo que eso se deshace de este problema es actualmente más importante. Tal vez esté atado por su compilador, pero use un estilo realmente antiguo de C ++ que podría ser modernizado. También mezcla estilo C con estilo C ++, que realmente no se recomienda.

Quiero ir con una solución como la primera arriba debido a la simplicidad y mostrarle 9988777665544333 semántica.

Vamos a pasar por sus archivos y unifíquelos para fines de demostración ( código fuente completo aquí ). También veamos cómo se puede manejar todo esto. Comenzamos con las definiciones de TPressure y TTemperature . ¡No tienes que Typedef Structures en C ++!

  struct TPressure {     int iPressureData; };  struct TTemperature {     int iTemperatureData; };   

no vamos a saltar en CSubject.h ! CRegisterableBase es bueno, pero a menos que no tenga la intención de modificar El valor observable, ¡no pases por referencia! (No veo por qué debería modificarlo)

  template <typename Observable> class CRegisterableBase { public:     virtual void Notify(const Observable&) = 0;     virtual ~CRegisterableBase() = default; };   

Un sujeto debe mantener una lista (o vector, lo que sea) de std::weak_ptr0 a objetos registrables. Yo elimino toda la lógica de salida para la demostración y se reduce a

  std::weak_ptr1  

Ahora, el sujeto tiene toda la lógica y el resto debe ser realmente simple.

  std::weak_ptr2  

y ahora un ejemplo std::weak_ptr3 Función:

  std::weak_ptr4  

Su std::weak_ptr5 La clase podría tomar sujetos por valor y simplemente reenviar los datos de presión y temperatura. Simplemente no vuelva a usar los punteros si no tiene que hacerlo. Por ejemplo, puede usar parámetros de plantilla de dos (o variados) en std::weak_ptr6 y combine sujetos arbitrarios. De esa manera, también puede pasar una std::weak_ptr7 (PRECAUCIÓN PARA COLGURAR otra vez) o un std::weak_ptr8 al sujeto.

¡Todavía hay formas de mejorar esto! Si todos los sujetos y observadores son conocidos por compilar el tiempo, Puede unir a los sujetos y observadores sin ninguna interfaz virtual y memoria de montón. Pero siento que primero debes aprender más la programación de C ++ - Ish.

 

The way how you use pointers is quite dangerous and C++ has tools to make this totally safe. The biggest problem of your implementation is the usage of possibly dangling pointers in your subject classes. But also your pointers in interfaces are totally unguarded against nullptrs. Just don't pass pointers through functions if you do not have to: pass them as references.

There are multiple ways to tackle the lifetime issues which your code could potentially face:

  • Subjects own their observers in some way (by value or shared pointer or whatever). That way observers never dangle, by definition.

  • Observers cancel their submission to their subjects in their destructors. That's a really dirty way, since it beats the purpose of the pattern. In that scenario not only subjects handle observers, but you either have some global instance which knows of all connections between subjects or observers themself know which subjects they have registered to. Eh... no.

  • Subjects hold only weak references in form of std::weak_ptr to their observers. A weak reference can tell whether some observer still lives and can be constructed from a std::shared_ptr.

I think that getting rid of this issue is currently most important. Maybe you are bound by your compiler, but you use really old C++ style which could be modernized. You also mix C-style with C++-style, which isn't really recommended.

I want to go with a solution like the first above because of simplicity and to show you std::shared_ptr semantics.

Let's go through your files and unify them for demonstration purpose (complete source code here). Lets also look at how all this can be handled. We start with the definitions of TPressure and TTemperature. You do not have to typedef structures in C++!

struct TPressure {     int iPressureData; };  struct TTemperature {     int iTemperatureData; }; 

No lets jump into CSubject.h! CRegisterableBase is good, but unless you do not intend to modify the observable value, don't pass by reference! (I do not see why you should modify it)

template <typename Observable> class CRegisterableBase { public:     virtual void Notify(const Observable&) = 0;     virtual ~CRegisterableBase() = default; }; 

A subject should hold a list (or vector, whatever) of std::shared_ptr to registrable objects. I remove all your output logic for demonstration and it boils down to

template <typename Observable> class CSubject { private:     using ObserverPointer = std::shared_ptr<CRegisterableBase<Observable>>;     std::vector<ObserverPointer> observers;  public:     bool Register(ObserverPointer observer) noexcept     {         if (!observer) return false; // check if it is empty         auto it = std::find(observers.begin(), observers.end(), observer);         if (it == observers.end()) {             observers.emplace_back(std::move(observer));             return true;         }         return false;     }      bool Unregister(const ObserverPointer& observer) noexcept     {         auto it = std::find(observers.begin(), observers.end(), observer);         if (it != observers.end()) {             observers.erase(it);             return true;         }         return false;     }      void NotifyObservers(const Observable& observable) const     {         for (auto& observer : observers) {             observer->Notify(observable);         }     }      decltype(auto) Observers() const noexcept { return observers; } }; 

Now the subject holds all the logic and the rest should be really simple.

class CPressureRegisterable : public CRegisterableBase<TPressure> { public:     void Notify(const TPressure& aPressure) override     {         // do something         std::cout << "Recieved pressure data: " << aPressure.iPressureData << '\n';     } };  class CTemperatureRegisterable : public CRegisterableBase<TTemperature> { public:     void Notify(const TTemperature& aTemperature) override     {         // do something         std::cout << "Recieved temperature data: " << aTemperature.iTemperatureData << '\n';     } }; 

And now an example main() function:

int main() {     auto p_observer = std::make_shared<CPressureRegisterable>();     CSubject<TPressure> subject_1;     subject_1.Register(p_observer);      // go and print "Recieved temperature data: 201\n"     TPressure p = {201};     subject_1.NotifyObservers(p); } 

Your CCombiRegister class could take subjects by value and just forward pressure and temperature data. Just don't use pointers again if you don't have to. For example, you could use two (or variadic many) template parameters in CCombiRegister and combine arbitrary subjects. That way you can also pass a std::reference_wrapper (caution for dangling again) or a std::shared_ptr to subject.

There are still ways to improve this! If all subjects and observers are known to compile time, you can bind subjects and observers without any virtual interface and heap memory. But I feel like you should first learn more C++-ish programming.

 
 
         
         

Relacionados problema

2  Implementación del patrón de observador para NOde.js  ( Implementation of observer pattern for node js ) 
Escribí una implementación del patrón de observador como parte de mi juego de ajedrez de batalla en línea : class Player attr_accessor :color, :pieces, ...

4  Despachador de eventos simple  ( Simple event dispatcher ) 
Aquí está mi primer despachador de eventos. Me gustaría obtener una revisión de estilo y estilo, así como algunas ideas para mejorar esta implementación (nuev...

3  Simple C ++ 11 asunto-observador  ( Simple c11 subject observer ) 
Edificio en la respuesta en C ++ Clase Miembro de la clase Call de devolución de llamada simple , i i He tratado de reunir un simple patrón de observador de ...

6  Plantilla observable en C ++ moderno  ( Observable template in modern c ) 
Estoy tratando de crear una clase de plantilla moderna para un observable genérico: typedef int SUBSCRIPTION_ID; template<typename EventType, typename Eve...

3  Programador construido con observables v3 (seguimiento) - ahora comprobable  ( Scheduler built with observables v3 follow up now testable ) 
Este es un segundo seguimiento a mi Anterior Uno sobre un Scheduler Construido con observables. Aunque el último estaba funcionando correctamente, solo ...

14  El patrón de diseño de observadores en Python, con pruebas unitarias  ( The observer design pattern in python with unit tests ) 
Continuando trabajando en la Head Primer diseño de patrones en un Esfuerzo para convertirse en un programador más eficiente y mejor de Python. La revisión d...

4  JS Cronómetro: ¿es esta una buena manera de implementar el patrón del observador?  ( Js stopwatch is this a good way to implement the observer pattern ) 
Estoy aprendiendo OOP y también estoy tratando de aprender e implementar algunos patrones de diseño. Esta pregunta es un seguimiento de Oop de la interfaz de...

1  Suscrito a múltiples fuentes en Rxjava  ( Subscribing to multiple sources in rxjava ) 
He usado Rxjava para observar múltiples fuentes y luego realizar acciones dependiendo de los valores de observables. Quiero saber si se puede simplificar aún ...

2  Observable  ( Observablequeue ) 
Estoy buscando comentarios sobre esto. public sealed class ObservableQueue<T> : IObservable<T>, IDisposable { private readonly object _lock = new objec...

6  Autobús de mensajes en C #  ( Message bus in c ) 
Escribí una clase couldBe4 cuyo único propósito es enviar mensajes de objeto a objeto sin un vínculo directo entre ellos. Me encontré con un problema con ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos