#ifndef __ZX_POSTOFFICE_H__ #define __ZX_POSTOFFICE_H__ /*--------------------------------------------------------------------------- * * Title : PostOffice Class based inter-object communication * * File Type : Implementation File * * Description : Templated version of the PostOffice Notification class structure * : * : * : * : * * References : http://www.chateau-logic.com/content/class-based-inter-object-communication * * Author : Richard Harrison (richard@zaretto.com) * * Creation Date : 18 March 2002 * * Version : $Header: $ * * Copyright © 2002 Richard Harrison All Rights Reserved. * *---------------------------------------------------------------------------*/ const int ZX_POSTOFFICE_NOTIFY = 'RHPO'; #include #include #include #include #include //#include typedef enum PostStatus { Success, Failure, Abort, Finished }; // // This is the base card that is sent around between unspecified and unknowing postoffice methods. // The structure we have is that anyone can hold onto a CardBase by using a Card(CardBase), which // will call the virtual function card_copy to make a real copy of the derived class. There // may well be a better more transparent way of implementing this functionality, i.e. I want // to pass around an oblique base pointer, which can be copied and held onto, possibly by copy constructors // and overloading operators, but this way is easier to understand. class CardBase { private: // nobble copy constructor CardBase(CardBase &r) { } protected: CardBase() { } public: virtual ~CardBase() { } virtual int get_id() const = 0; virtual CardBase *copy() = 0; }; template CardBase *card_copy(T* that) { T *b = new T; *b = *that; return b; } // // Class used to store a card for later usage. class Card { private: ManagedObject card; public: Card(Card &r) // Copy constructor allowed on this... { card = r.card->copy(); } Card (CardBase *r) { card = r->copy(); } Card (CardBase &r) { card = r.copy(); } virtual ~Card () { } CardBase *operator->() { return &*card; } CardBase &operator*() { return *card; } }; class RecipientBase { public: virtual ~RecipientBase() { } virtual PostStatus receive_card (const CardBase &) = 0 { }; virtual void joined (class PostOffice *p) = 0 { } }; class PostOffice { protected: typedef std::list RecipientList; RecipientList recipient_list; public: void join (RecipientBase *r) { if (r) { recipient_list.push_back(r); r->joined(this); } } void resign (RecipientBase *r) { if (recipient_list.size()) recipient_list.remove(r); } PostStatus notify_all(const CardBase &c) { for (RecipientList::iterator i = recipient_list.begin(); i != recipient_list.end(); i++) { switch ((*i)->receive_card(c)) { case Success: case Failure: break; case Abort: return Abort; case Finished: return Finished; } } return Success; } }; class Recipient : public RecipientBase { protected: typedef std::list PostOfficeList ; PostOfficeList postoffice_list; public: virtual void joined (PostOffice *p) { postoffice_list.push_back(p); } ~Recipient() { // for (PostOfficeList::iterator i = postoffice_list.begin(); i != postoffice_list.end(); i++) // { // (*i)->resign(this); //} // postoffice_list.clear(); } }; class Sender { protected: typedef std::list PostOfficeList ; PostOfficeList postoffice_list; public: virtual void joined (PostOffice *p) { postoffice_list.push_back(p); } void notify(const CardBase &s) { for (PostOfficeList::iterator i = postoffice_list.begin(); i != postoffice_list.end(); i++) { (*i)->notify_all(s); } } }; class RecipientSender : public Recipient { public: void notify(const CardBase &s) { for (PostOfficeList::iterator i = postoffice_list.begin(); i != postoffice_list.end(); i++) { (*i)->notify_all(s); } } void q_notify(CardBase &s); }; class NotifyQueueElement { protected: RecipientSender *rs; Card s; public: NotifyQueueElement(RecipientSender *rs, Card c): s(c), rs(rs) { } NotifyQueueElement(Card c): s(c), rs(0) { } void notify() { if (rs) rs->notify(*s); } }; class NotifyQueueManager { public: typedef std::vectorNotifyQueue; static NotifyQueue q; static void q_notify(RecipientSender *sender, CardBase &card) { NotifyQueueElement *nqe = new NotifyQueueElement(sender, card); q.push_back(nqe); } static void q_process(CardBase &s) { NotifyQueue::iterator i = q.begin(); while (i != q.end()) { (*i)->notify(); delete *i; } q.clear(); } }; struct ZX_POSTOFFICE_EVENT : public UI_EVENT { public: NotifyQueueElement *nqe; ZX_POSTOFFICE_EVENT(NotifyQueueElement *n) ; } ; inline void RecipientSender::q_notify(CardBase &s) { // NotifyQueueManager::q_notify(this, s); ZX_POSTOFFICE_EVENT(new NotifyQueueElement(this, s)); } class GlobalRecipient : public Recipient { protected: public: static PostOffice gpo; GlobalRecipient() { gpo.join(this); } ~GlobalRecipient() { gpo.resign(this); } static PostStatus notify_all(const CardBase &c) { return gpo.notify_all(c); } }; #endif //__ZX_POSTOFFICE_H__