2017-04-21 5 views
1

私はテンプレート、訪問者パターン、およびCRTPの助けを借りてメッセージングシステムを作成しようとしています。私はこれらのコンセプトを理解していますが、私は "失われた"タイプを取り戻さなければならない状況にあります。私はBaseクラスを持っていて、Derived<T>を探しています。それは(たとえそれが1つのタイプと考えられていても)Tが何でもよいと推測する "2つの"タイプのものです(Derived)。訪問者パターンのクラステンプレートのタイプを取得する

私は2番目のビジターパターンを使用しようとしましたが、これは重く狂っているようですが、実際の解決策は見つかりませんでした。たとえそれがゲーム関連であっても、それはまるで一例であり、私が想定している他のプログラムにも適用できます。私はそれを別のコンテキストで公開することはできません。ここで

は、私は(不必要な例で)使用されるネーミングです:

  • SubscriberBaseは、(ネットワーククライアントのような)メッセージを送信し、受信したクラスです
  • Broadcasterは、加入者間のブリッジである(ネットワークのようにスイッチ/サーバ)であり、ベクトルはSubscriberBaseです。

私は、この最小限のコードを思い付いた:問題はタイプTHE_ACTUAL_SUBSCRIBER_TYPEある

class SubscriberBase {}; 

class Broadcaster { 
    std::vector<SubscriberBase*> subscribers; 
public: 
    template<typename TMessage> 
    void broadcast(TMessage& message) { 
     for(auto subscriber : subscribers) { 

      // <<< Here is my problem <<< 
      message.accept<THE_ACTUAL_SUBSCRIBER_TYPE>(subscriber); 

     } 
    } 

    void attach(SubscriberBase* subscriber) { 
     subscribers.push_back(subscriber); 
    } 
}; 

//Base class for handling messages of any type 

template<typename TMessage> 
class MessageHandler { 
public: 
    virtual void handleMessage(TMessage& message) {} 
}; 

//Base class for messages 

template<typename TMessage> 
class Message { 
    friend class Broadcaster; 
private: 

    //Visitor pattern with CRTP 
    template<typename TSubscriber> 
    void accept(TSubscriber* subscriber) { 
     subscriber->handleMessage(*static_cast<TMessage*>(this)); 
    } 

}; 

//Messages 

struct EntityCreated : public Message<EntityCreated> {}; 
struct EntityDestroyed : public Message<EntityDestroyed> {}; 
struct BurnAllGummyBears : public Message<BurnAllGummyBears> {}; 

//Subscribers 

class EntityCache : public SubscriberBase, 
    public MessageHandler<EntityCreated>, 
    public MessageHandler<EntityDestroyed>, 
    public MessageHandler<BurnAllGummyBears> 
{ 
public: 
    void handleMessage(EntityCreated& message) override { /* add to cache */ } 
    void handleMessage(EntityDestroyed& message) override { /* remove from cache */ } 
    //does not override BurnAllGummyBears because it's not relevant for EntityCache 
}; 

。それはどんな "具体的な"加入者でもあり得る。なし成功を収めて

class SubscriberBase {}; 

template<typename TSubscriber> 
class Subscriber : public SubscriberBase { /* some other visitor pattern ? */ }; 

class EntityCache : public Subscriber<EntityCache>, /* ... */ 

:この場合には、それはたとえばEntityCacheまたはLoggerCommandRecorderのような何か他のもののためになる...

私は別のクラスに結合された別のCRTPを使用しようとしました。

すべてのアイデアが評価され、あなたに感謝:)

答えて

0

を、私はこのアイデアをあきらめたと思った「まあ、私のKISS ..」ので、私は、シンプルなデザインのために行くために、通常、クリーンなアプローチを決めました正常でクリーンなコード。

//Messages 
struct EntityCreated {}; 
struct EntityDestroyed {}; 
struct ChopAllTrees {}; 
struct MakeGummyBearsEvil {}; 

//Subscriber is now a base class containing all of the message handlers 
class Subscriber { 
public: 
    virtual void handleMessage(EntityCreated& msg) {} 
    virtual void handleMessage(EntityDestroyed& msg) {} 
    virtual void handleMessage(ChopAllTrees& msg) {} 
    virtual void handleMessage(MakeGummyBearsEvil& msg) {} 
}; 

class Broadcaster { 
    std::vector<Subscriber*> subscribers; 
public:  
    template<typename M> 
    void broadcast(M& msg) { 
     for(auto subscriber : subscribers) { 
      subscriber->handleMessage(msg); 
     } 
    } 

    template<typename M> 
    void broadcast(M&& msg) { 
     M owner(msg); 
     broadcast(owner); 
    } 

    void attach(Subscriber* subscriber) { 
     auto it = std::find(subscribers.begin(), subscribers.end(), subscriber); 
     if(it == subscribers.end()) { 
      subscribers.push_back(subscriber); 
     } 
    } 

    void detach(Subscriber* subscriber) { 
     auto it = std::find(subscribers.begin(), subscribers.end(), subscriber); 
     if(it != subscribers.end()) { 
      subscribers.erase(it); 
     } 
    } 
}; 

//Subscribers simply inherits from Subscriber and overrides interesting handlers 
class EntityCache : public Subscriber { 
    void handleMessage(EntityCreated& msg) override { 
     std::cout << "Handling creation\n"; 
    } 
    void handleMessage(EntityDestroyed& msg) override { 
     std::cout << "Handling destruction\n"; 
    } 
}; 

class Eviler : public Subscriber { 
    void handleMessage(MakeGummyBearsEvil& msg) override { 
     std::cout << "Gummy bears are now evil!\n"; 
    } 
}; 

int main() { 
    EntityCache entityCache; 
    Eviler eviler; 

    Broadcaster broadcaster; 
    broadcaster.attach(&entityCache); 
    broadcaster.attach(&eviler); 

    EntityCreated entityCreated; 

    broadcaster.broadcast(entityCreated); //lvalue test 
    broadcaster.broadcast(MakeGummyBearsEvil()); //rvalue test 

    broadcaster.detach(&eviler); 

    broadcaster.broadcast(EntityDestroyed()); 
    broadcaster.broadcast(MakeGummyBearsEvil()); //no effect 
} 

それが問題を解決して以来、私はこの答えを受け入れるんだけど、私はまだそれを行う方法について興味があるため、誰もが(おそらくない)、過去にこの問題が発生し、それを処理した場合、お気軽に答えると私はそれを受け入れるだろう。

関連する問題