我想實現觀察者模式到我的項目中。觀察者const正確性
想象簡單類方法
const Buffer * data() const
{
if (m_data)
return m_data;
// read some data from input
m_data = fstream.read(1000);
// subscribe to our buffer
m_data->Subscribe(this);
return m_data;
}
此方法用於讀取輸入數據,但操作可能是耗時的,因此延遲。
類緩衝區是std :: vector之上的簡單包裝,它在數據被更改時通知觀察者。
當緩衝區數據發生變化時,需要通知包含類。 但是,由於此方法被標記爲const,我無法訂閱緩衝區。
我能想出3個解決方案:
遠離鑄造常量性
// subscribe to our buffer
m_data->Subscribe(const_cast<Object*>(this));
我不知道,這是否是正確的,但它的工作原理。
通知方法2.改變常量性和觀察員
vector<const IModifyObserver*> m_observers;
void Subscribe(const IModifyObserver* observer);
void Unsubscribe(const IModifyObserver* observer)
virtual void ObserveeChanged(IModifyObservable*) const override
{
m_dirty = true;
}
這其中有一個倒臺,如果我需要改變,他們都必須是可變的特性,所有的功能我調用必須是常量,這也沒有任何意義。來自世界各地的
Buffer * data();
bool Equals(Object& other);
Buffer* m_data;
刪除常量這很可能意味着,我必須從整體解決方案中刪除常量,因爲我不能事件調用的Equals兩個不同的const對象。
如何正確解決這個問題?
全碼:
#include <vector>
using namespace std;
class IModifyObservable;
// class for receiving changed notifications
class IModifyObserver
{
public:
virtual void ObserveeChanged(IModifyObservable* observee) = 0;
virtual ~IModifyObserver() = 0;
};
// class for producing changed notifications
class IModifyObservable
{
public:
// Add new subscriber to notify
void Subscribe(IModifyObserver* observer)
{
m_observers.push_back(observer);
}
// Remove existing subscriber
void Unsubscribe(IModifyObserver* observer)
{
for (auto it = m_observers.begin(); it != m_observers.end(); ++it) {
if (observer == *it) {
m_observers.erase(it);
break;
}
}
}
// Notify all subscribers
virtual void OnChanged()
{
auto size = m_observers.size();
for (decltype(size) i = 0; i < size; ++i) {
m_observers[i]->ObserveeChanged(this);
}
}
virtual ~IModifyObservable() = 0;
private:
vector<IModifyObserver*> m_observers;
};
IModifyObserver::~IModifyObserver() {}
IModifyObservable::~IModifyObservable() {}
// Example class implementing IModifyObservable
class Buffer : public IModifyObservable
{
private:
vector<char> m_data;
};
// Example class implementing IModifyObserver
class Object : public IModifyObserver
{
public:
// Both share implementation
//Buffer * data();
const Buffer * data() const
{
// Just read some data
//m_data = fstream.read(1000);
// Subscribe to our buffer
m_data->Subscribe(this);
return m_data;
}
virtual void ObserveeChanged(IModifyObservable*) override
{
m_dirty = true;
}
// This is just for example, why do I need const data method
bool Equals(const Object& other) const { return data() == other.data();
}
private:
mutable Buffer* m_data = new Buffer();
bool m_dirty;
};
int main()
{
Object obj1;
Object obj2;
auto data1 = obj1.data();
auto data2 = obj2.data();
bool equals = (obj1.Equals(obj2));
}
我不是常規專家,所以我沒有發佈答案,但我會做選項1:確保你的'ObserveeChanged()'實際上不修改'this',然後拋棄'const'來實現接口。 – rodrigo
'm_data-> Subscribe(this);'不應該在getter中完成。另外,'m_data = fstream.read(1000)''已經打破了'const'部分。 – Jarod42
m_data被標記爲可變。這在每種緩存方法中都是常見的做法。應該在哪裏「m_data->訂閱(this);」叫做? – Gotcha