MUP1+Øvelse+8+Msg+System

toc =The Message System= : Færdige system.

MessageHandler.h
code format="cpp" class MessageHandler : public Thread { public: MessageHandler(std::string); virtual ~MessageHandler; void attachTo(MessageType); virtual void handleMessage(Message*) = 0; protected: void run; private: Mailbox* mailbox; std::vector attachedMsgs; }; code

MessageHandler.cpp
code format="cpp" MessageHandler::MessageHandler(std::string name): Thread(name) {	mailbox = new Mailbox(10); }

MessageHandler::~MessageHandler {	std::vector::iterator it = attachedMsgs.begin; for (it != attachedMsgs.end; ++it) Message::detach(*it, mailbox); }

void MessageHandler::attachTo(MessageType t) { attachedMsgs.push_back(t); Message::attach(t, mailbox); }

void MessageHandler::run {	while (1) {		MarshalledMessage mm = mailbox->get; Message* msg = reinterpret_cast(&mm); handleMessage(msg); } } code

Message.h
Det er vigtigt at er  da det er størrelse af de nedarvede vi gerne vil have. Faktisk kunne i Message godt være pure virtual. Men det har jeg ikke gjort. code format="cpp" class Message { public: Message(MessageType); virtual ~Message; static void attach(MessageType, Mailbox*); static void detach(MessageType, Mailbox*); void send; MessageType getType; protected: virtual unsigned int getSize; private: static std::map*> > observers; MessageType type; }; code

Message.cpp
Læg mærke til at er initialiseret i global scope, da den er static og kompileren ellers ikke kan finde ud af hvem der ejer den. Sagt på en lidt anden måde, hvem der skal destructe den. code format="cpp" std::map*> > Message::observers;

Message::Message(MessageType type) {	this->type = type; }

Message::~Message { // TODO Auto-generated destructor stub }

MessageType Message::getType {	return type; }

unsigned int Message::getSize {	return sizeof(*this); }

void Message::detach(MessageType messageType, Mailbox *mailbox) {	observers[messageType].remove(mailbox); }

void Message::attach(MessageType messageType, Mailbox *mailbox) {	observers[messageType].push_back(mailbox); }

void Message::send {	MarshalledMessage msg; memcpy(&msg, this, getSize); std::list*>::iterator iter = observers[type].begin; for (iter != observers[type].end; ++iter) (*iter)->put(msg); } code

Speed message
code format="cpp" class SpeedMessage : public Message { public: SpeedMessage : Message(SPEED_MSG) {} ~SpeedMessage {} unsigned int getSpeed {		return speed; }	void setSpeed(unsigned int speed) {		this->speed = speed; } protected: virtual unsigned int getSize {		return sizeof(*this); } private: unsigned int speed; };

std::istream& operator>>(std::istream &stream, SpeedMessage& obj) {	unsigned int speed; do { std::cout << "Enter speed: "; stream >> speed; if (stream.fail) {			std::cout << "Invalid input! Try again..." << std::endl; stream.clear; stream.ignore(std::numeric_limits::max, '\n'); continue; }		break; } while (1); obj.setSpeed(speed); return stream; } code

Heading message
code format="cpp" class HeadingMessage : public Message { public: HeadingMessage : Message(HEADING_MSG) {} ~HeadingMessage {} unsigned int getHeading {		return heading; }	void setHeading(unsigned int heading) {		this->heading = heading; } protected: virtual unsigned int getSize {		return sizeof(*this); } private: unsigned int heading; };

std::istream& operator>>(std::istream &stream, HeadingMessage& obj) {	unsigned int heading; do { std::cout << "Enter heading: "; stream >> heading; if (stream.fail) {			std::cout << "Invalid input! Try again..." << std::endl; stream.clear; stream.ignore(std::numeric_limits::max, '\n'); continue; }		break; } while (1); obj.setHeading(heading); return stream; } code

Speed handler
code format="cpp" class SpeedHandler : public MessageHandler { public: SpeedHandler : MessageHandler("Speed Handler") { attachTo(SPEED_MSG); }	virtual ~SpeedHandler {} void handleMessage(Message* msg) {		SpeedMessage* m = dynamic_cast(msg); // safe downcast if (m) {			std::cout << std::endl << "Got speed message with speed: " << m->getSpeed << std::endl; }	} }; code

Heading handler
code format="cpp" class HeadingHandler : public MessageHandler { public: HeadingHandler : MessageHandler("Message Handler") { attachTo(HEADING_MSG); }	virtual ~HeadingHandler {} void handleMessage(Message* msg) {		HeadingMessage* m = dynamic_cast(msg); // safe downcast if (m) {			std::cout << std::endl << "Got heading message with heading: " << m->getHeading << std::endl; }	} }; code

Test
code Enter (A)irspeed, (H)eading or (Q)uit: a Enter speed: 200 Enter (A)irspeed, (H)eading or (Q)uit: Got speed message with speed: 200 h Enter heading: 300 Enter (A)irspeed, (H)eading or (Q)uit: Got heading message with heading: 300 A Enter speed: 100 Enter (A)irspeed, (H)eading or (Q)uit: Got speed message with speed: 100 q code Det virker som det skal.

Extending the application
Nu skal systemet udvides med endnu en handler som abonnere på både og. Det er nemt! Vi skal blot skrive en handler klasse og så tilføje dette til vores main: Done.

LogHandler
code format="cpp" class LogHandler : public MessageHandler { public: LogHandler : MessageHandler("Log Handler") { attachTo(SPEED_MSG); attachTo(HEADING_MSG); }	virtual ~LogHandler {} void handleMessage(Message* msg) {		if (dynamic_cast<SpeedMessage*>(msg)) {			SpeedMessage* m = dynamic_cast<SpeedMessage*>(msg); // safe downcast std::cout << std::endl << "Got speed message with speed: " << m->getSpeed << std::endl; return; }		if (dynamic_cast<HeadingMessage*>(msg)) {			HeadingMessage* m = dynamic_cast<HeadingMessage*>(msg); // safe downcast std::cout << std::endl << "Got heading message with heading: " << m->getHeading << std::endl; return; }	} }; code

Test
code format="cpp" Enter (A)irspeed, (H)eading or (Q)uit: a Enter speed: 200 Enter (A)irspeed, (H)eading or (Q)uit: Got speed message with speed: 200

Got speed message with speed: 200 h Enter heading: 9001 Enter (A)irspeed, (H)eading or (Q)uit: Got heading message with heading: 9001

Got heading message with heading: 9001 q code Konklusion: **NERDGASM!!!**