一個主題可能有多個觀察者,例如技術分析 ( 觀察者1 ),當日走勢 (觀察者 2) 等多個觀察者關注相同的主題。
因為上一篇的設計沒有 Observer 抽象基礎類別,為了滿足多個觀察者的需求,或許會想到可以新增成員變數 ViewType 來區分不同的觀察者,擁有 $View_TA 的是技術分析,而擁有 $View_Tick 的是當日走勢。
enum class ViewType
{
$View_TA, // 技術分析
$View_Tick // 當日走勢
};
class CObserver final // 台積電資料的觀察者
{
public:
CObserver(ViewType eType) : m_eType(eType)
{}
public:
void Update(CTSMCStockSubject* pSubject)
{}
private:
ViewType m_eType;
};
int main()
{
auto ob1 = std::make_shared<CObserver>(ViewType::$View_TA); // 技術分析
auto ob2 = std::make_shared<CObserver>(ViewType::$View_Tick); // 當日走勢
CTSMCStockSubject subject;
subject.Subscribe(ob1);
subject.Subscribe(ob2);
subject.Notify();
subject.Unsubscribe(ob2);
subject.Unsubscribe(ob1);
return 0;
}
但這樣勢必 CObserver 內會有許多 if … else … 的判斷敘述去處理 $View_TA 及 $View_Tick 的分支 case,或許還有人進一步想到用狀態模式 (State pattern) 來重構 CObserver。
其實這些都是本末倒置,正確做法就是需要有 Observer 抽象基礎類別的存在,不同的觀察者繼承此抽象基礎類別並實作之,對應的處理邏輯寫在各自的衍生類別內,消除了 CObserver 內可能的 if (ViewType == $View_TA) else … 的判斷處理。
class IObserver // Observer 抽象基礎類別
{
public:
virtual ~IObserver() = 0
{}
public:
virtual void Update(CTSMCStockSubject* pSubject) = 0;
};
// 技術分析
class CTAViewObserver : public IObserver
{
public:
virtual void Update(CTSMCStockSubject* pSubject) override
{}
};
// 商品盤勢
class CTickViewObserver : public IObserver
{
public:
virtual void Update(CTSMCStockSubject* pSubject) override
{}
};
CTSMCStockSubject 類別內所有的 CObserver 也要修改成 IObserver。
class CTSMCStockSubject final // 台積電資料的主題
{
public:
void Subscribe(const std::shared_ptr<IObserver>& ob)
{
m_observers.emplace(ob);
}
void Unsubscribe(const std::shared_ptr<IObserver>& ob)
{
m_observers.erase(ob);
}
void Notify()
{
for (auto& ob : m_observers)
{
ob->Update(this);
}
}
private:
std::set<std::shared_ptr<IObserver>> m_observers;
};
使用方式改為直接 new 出對應的 class,不必再使用 ViewType 區分,程式更為清楚明確。
int main()
{
auto ob1 = std::make_shared<CTAViewObserver>(); // 技術分析
auto ob2 = std::make_shared<CTickViewObserver>(); // 當日走勢
CTSMCStockSubject subject;
subject.Subscribe(ob1);
subject.Subscribe(ob2);
subject.Notify();
subject.Unsubscribe(ob2);
subject.Unsubscribe(ob1);
}
留言
張貼留言