2016-08-28 45 views
0

我實現一個裝飾圖案按照here的示例裝飾包裝的一些成員:I裝飾模式:如何可以調用(背面)由核心類

  • 類別:是接口類,通用於既類和裝飾基
  • A:是核心類
  • D:是裝飾基
  • XYZ:從裝飾基類繼承和擴展核心類的功能動態

有在A類中的一個方法(A::endTraining()),在定時器變量結束時觸發(也存在於類A中)。此方法需要調用X,YZ類的某些成員。
可能嗎?這是不錯的做法嗎?怎麼樣?

例如,是否創建了一種機制來註冊指針到XYZ::endTrainingA一個正確的方法?

(只顯示相關的位)

typedef void (D::*pCallback_fn)(void); 

class I 
{ 
    public: 
    virtual void endTraining() = 0; 
    virtual void regTrainingCallbacks(pCallback_fn ptrFn) = 0; 
}; 

class A: public I { 
    public: 

    void endTraining() { 
     //do stuff 
     //then do stuff in D (and its derivatives) 
     // by iterating through fnList 
    } 
    void regTrainingCallbacks(pCallback_fn ptrFn) 
    { 
     fnList.push_back(ptrFn); 
    } 
    private: 
    std::list<pCallback_fn> fnList; 
}; 

class D: public I { 
    public: 
    D(I *inner) { 
     m_wrappee = inner; 
    } 
    void regTrainingCallbacks(pCallback_fn ptrFn) 
    { 
     m_wrappee->regTrainingCallbacks(ptrFn); 
    } 
    private: 
    I *m_wrappee; 
}; 

class X /*,Y,Z*/ : public D { 
    public: 
    X(I *core): D(core) 
    { 
     D::regTrainingCallbacks(this->*endTraining()); // 
    } 
    private: 
    void endTraining(){ 
     //do stuff when called by A::endTraining() through D 
    } 
}; 

有什麼可以代替呢?

+0

您還需要一個對象'D'來調用'fnList'中註冊的方法。實際上,您可以通過添加另一個虛擬方法'virtual void regDecorator(D * decorator)',在'A'類中註冊所有裝飾器,該方法將由'D'的構造函數調用。這個方法將在A中通過除了'fnList'之外的字段中的註冊來實現。然後'A :: endTraining'可以在所有裝飾器上調用'fnList'的所有回調方法。如果您只想通知已經註冊了回叫的'X'裝飾器或'X',它可能會有所不同。 – Franck

+1

爲什麼不使用'std :: function's列表而不是指向成員方法的指針列表? – skypjack

+0

@Franck'regDecorator'似乎是一個好主意,但是我必須檢查XYZ是否都有一個「endTraining()'方法,我正在尋找有關如何做但不能找到的信息。爲'null'? – nass

回答

1

解決原設計中的一個錯誤,其中「培訓師」(實體註冊培訓回調)本身必須是回調(是否有任何理由通知者 - 前類A - 必須是回調本身?) 。

我改變了類名來證明他們的責任。

MainTrainingProcess將替換原來的class A(其實例將被D -es包裝)和D本身。

class EndTrainingListener 
{ 
public: 
    virtual ~EndTrainingListener() { } 

    virtual void endTraining()=0; 
}; 

class ITrainingProcess 
{ 
public: 
    virtual ~ITrainingProcess() { } 
    virtual void regTrainingCallbacks(EndTrainingListener* callback) = 0; 
}; 

class MainTrainingProcess : public ITrainingProcess { 
public: 
    virtual ~MainTrainingProcess() { 
    // destroy other resources used during training 
    } 

    virtual void regTrainingCallbacks(EndTrainingListener* callback) { 
    this->listeners.push_back(callback); 
    } 

    void train() { 
    // do training stuff 
    // ... 
    // do my specific actions at the end of training 
    // ... 

    // finish by notifying all listeners 
    this->atEndTraining(); 
    } 
protected: 
    void atEndTraining() { 
    for(auto l : this->listeners) { 
     l->endTraining(); 
    } 
    } 

    std::list<EndTrainingListener*> listeners; 
}; 

class X /*Y, Z*/ : public EndTrainingListener { 
public: 
    virtual ~X(); 

    virtual void endTraining() { 
    // do specific stuff 
    } 
};