我一直在项目中成功使用Subject-Observer模式。随着Subject-Observer和消息类型的数量增长到5+,我发现自己为每个代码模式重复相同的代码模式。我正在尝试切换到Subject-Observer模式的类模板。但我仍然遇到一个我无法解决的编译错误(尽管付出了努力):
Building file: ../main.cpp
Invoking: GCC C++ Compiler
g++ -std=c++0x -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
../main.cpp: In instantiation of ‘Observer<T_subject, T_message>::~Observer() [with T_subject = RotationSubject; T_message = long unsigned int]’:
../main.cpp:49:7: required from here
../main.cpp:39:15: error: invalid conversion from ‘Observer<RotationSubject, long unsigned int>* const’ to ‘RotationObserver*’ [-fpermissive]
~Observer(){ subject->UnregisterObserver( this ); }
^
../main.cpp:10:7: error: initializing argument 1 of ‘void Subject<T_observer, T_message>::UnregisterObserver(T_observer*) [with T_observer = RotationObserver; T_message = long unsigned int]’ [-fpermissive]
void UnregisterObserver( T_observer* observer ){
^
make: *** [main.o] Error 1
最小的工作示例代码是:
#include <vector>
template <class T_observer, typename T_message> class Subject
{
public:
void RegisterObserver( T_observer* observer ){
observers.push_back(observer);
}
void UnregisterObserver( T_observer* observer ){
for (auto itr = begin(observers); itr != end(observers); itr++){
if (*itr == observer){
itr = observers.erase(itr);
if (itr == observers.end()) break;
}
}
}
void NotifyObservers( T_message message ){
for(auto const& itr : observers){
itr->ReceiveMessage( message );
}
}
std::vector < T_observer * > observers;
};
template <class T_subject, typename T_message> class Observer
{
public:
Observer( T_subject* subject )
: subject( subject )
{
subject->RegisterObserver( this );
}
~Observer(){ subject->UnregisterObserver( this ); }
virtual void ReceiveMessage( T_message message ) {};
// Observer sub-classes define ReceiveMessage
T_subject* subject;
};
class RotationSubject;// forward declaration prevents circular dependency
class RotationObserver : public Observer< RotationSubject, unsigned long>
{
public:
RotationObserver( RotationSubject* rotation_subject );
};
class RotationSubject : public Subject< RotationObserver, unsigned long>
{ };
int main(int argc, char * argv[]){
RotationSubject* pRotSubject = new RotationSubject( );
RotationObserver* pRotObserver = new RotationObserver( pRotSubject );
pRotObserver->~RotationObserver();
return 0;
}
目的是定义从这些基类模板派生的子类,如RotationSubject
和RotationObserver
所示。类型标识符T_observer
和T_subject
的动机是具体关于哪些子类可以配对,例如RotationObservers
只应观察RotationSubjects
,并接收轮播消息类型(在此示例中T_message
为unsigned long
。)
如果我正确阅读了错误消息,Observer<RotationSubject, long unsigned int>* const
不 a RotationObserver*
,或者编译器不知道如何转换。
我探讨了循环依赖和const作为原因,但没有成功。
请帮助我了解此错误消息的原因,并在可能的情况下进行最小化修改。这是我的主要问题。
我对完全不同的设计持开放态度,并提出改进建议。
答案 0 :(得分:2)
您正在放弃const
限定词。如果没有const_cast
这是一个很好的理由,你就无法做到这一点。
你也试图转换错误&#34;方向。并非每个Observer< RotationSubject, unsigned long>
都必须是RotationObserver
,尽管反之亦然。您可以使用dynamic_cast
(或使用static_cast
和承诺)。
答案 1 :(得分:1)
进一步搜索显示了一些与模板化主观察器模式具体相关的有用链接: (https://www.codeproject.com/Articles/3267/Implementing-a-Subject-Observer-pattern-with-templ) (Template based Subject Observer pattern - Should I use static_cast or dynamic_cast) (Should I use dynamic cast in the subject observer pattern with templates)
以下代码是有效的更正版本。它源自第一个链接。根据@BoundaryImposition的答案,它在模板化的Subject :: NotifyObservers()方法中使用static_cast
来获取指向 Subject子类的指针。我对这个概念不是很满意,但它确实有效。根据我的理解,魔法酱是使用Subject
中的Curiously Recurring Template Pattern。具体为class Temperature : public Subject<Temperature>
(为清楚起见,删除了第二个模板标识符)。在我使用class RotationSubject : public Subject<RotationObserver>
之前,这是一个完全不同的继承。 Observer
子类PanicSiren
也有不同的继承。
请注意,我的模板会将RegisterObserver
和UnregisterObserver
移至Observer
ctor和dtor。不是必需的,只是我喜欢的方式。我还添加了消息类型模板标识T_message
,它允许各种消息类型。
我很高兴,因为预期的设计是在没有大量重写的情况下实现的:)。
#include <vector>
#include <iostream>
template <typename T_subject, typename T_message> class Observer{
public:
Observer( T_subject* subject ) : subject(subject) { subject->RegisterObserver( *this ); }
virtual ~Observer() { subject->UnregisterObserver( *this ); }
virtual void ReceiveMessage( T_subject* subject, T_message message ) = 0;// =0 requires subclasses to define
T_subject* subject;
};
template <class T_subject, class T_message> class Subject{
public:
virtual ~Subject() {}
void NotifyObservers( T_message message ){
typename std::vector<Observer<T_subject,T_message> *>::iterator it;
for ( it=m_observers.begin(); it!=m_observers.end(); ++it){
T_subject* this_subject_subclass = static_cast<T_subject*>(this);// pointer to _subclass_ type, curiously not yet defined ;)
(*it)->ReceiveMessage( this_subject_subclass, message );
}
}
void RegisterObserver( Observer<T_subject,T_message> &observer ){
m_observers.push_back( &observer ); }
void UnregisterObserver( Observer<T_subject,T_message> &observer ){
for (auto itr = begin(m_observers); itr != end(m_observers); itr++){
if (*itr == &observer){
itr = m_observers.erase(itr);
if (itr == m_observers.end()) break;
}
}
}
private:
std::vector<Observer<T_subject,T_message> *> m_observers;
};
class Temperature : public Subject<Temperature,unsigned long> {};
class PanicSiren : public Observer<Temperature,unsigned long>
{
public:
PanicSiren(Temperature* subject)
: Observer<Temperature,unsigned long>::Observer(subject) {}
void ReceiveMessage( Temperature *subject, unsigned long message ){
std::cout << "Temperature changed to " << message <<", sounding the siren"
<< std::endl;
}
};
int main(int argc, char * argv[]){
Temperature* temp = new Temperature();
PanicSiren* panic = new PanicSiren( temp );
temp->NotifyObservers( 42 );
return 0;
}