2017-04-21 20 views
1

템플릿, 방문자 패턴 및 CRTP를 사용하여 메시징 시스템을 작성하려고합니다. 나는 이러한 개념을 이해하지만 여전히 "잃어버린"유형을 찾아야하는 상황에 처해 있습니다. Base 클래스가 있으며 Derived<T>을 찾고 싶습니다. 그것은 "이 무엇이든 될 수 있음을 추론하는"두 가지 유형입니다 (T은 아무 것도 될 수 있음). (단 하나의 유형으로 간주 되더라도).방문자 패턴에 클래스 템플릿 유형 가져 오기

두 번째 방문객 패턴을 사용하려고했는데 무겁고 미친 것처럼 보였지만 어떤 해결책도 찾지 못했습니다. 게임과 관련이 있더라도, 예를 들어 다른 프로그램에 적용 할 수 있습니다. 다른 컨텍스트에서이 프로그램을 노출 할 수는 없습니다.

  • SubscriberBase를 전송하고, 네트워크와 같은 (
  • Broadcaster 가입자 사이의 다리 (네트워크 클라이언트 같은) 메시지를 수신하는 클래스이다 : 여기

    는 (불필요한 예)와 I 사용한 명칭 인 스위치/서버)이며 벡터가 SubscriberBase입니다.

나는이 최소한의 코드를 내놓았다 :

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 
}; 

문제는 유형 THE_ACTUAL_SUBSCRIBER_TYPE입니다. 그것은 "구체적인"가입자 일 수 있습니다. 성공하지

class SubscriberBase {}; 

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

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

:이 경우에는

내가 다른 클래스와 결합 다른 CRTP를 사용하려고 ... 예를 EntityCache 또는 Logger, CommandRecorder 같은 뭔가 다른 것입니다.

모든 아이디어 감사합니다, 당신을 :) 감사

답변

0

나는이 생각에 포기하고 "그럼, 내 키스 .."생각 그래서 간단한 디자인 가기로 결정, A에 대한 정상 및 청소 방법 정상적이고 깨끗한 코드.

//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 
} 

이 문제를 해결하기 때문에 나는이 대답을 받아들이는거야,하지만 사람이 과거에이 문제가 발생하면 이후로는 (아마), 그것을 수행하는 방법에 여전히 관심이 있으며 주시기 처리 대답하고 받아 들일 것입니다.