Table of Contents
- Introduction
- Overview
- Why Intercom?
- Structure
- C++ Implementation
- Typical Usages
Introduction
The Intercom pattern is a design pattern used in computer programming to observe the state of an object in a program. It is related to the principle of implicit invocation. This pattern is mainly used to implement a distributed event handling system. In some programming languages, the issues addressed by this pattern are handled in the native event handling syntax. This is a very interesting feature in terms of real-time deployment of applications.
Overview
The essence of this pattern is that one or more objects (called observers or listeners) are registered (or register themselves) to observe an event that may be raised by the observed object (the subject). (The object that may raise an event generally maintains a collection of the observers.)
Why Intercom?
I have searched design patterns where my subject and observer can be changed at any time, but I failed. I did not find any design pattern where anyone can subject and one can observe. At last I analyzed that term and found a solution to that. In my pattern anyone can subject [to notify its observers] and anyone observe [receive message from subject]. In my pattern, all of the classes which need to send and receive messages can only be inherited from the Subject
class and that is enough.
Source Code using Intercom Pattern
=====================================================
#include "stdafx.h"
#include "IBaseView.h"
#include "IModel.h"
int main(int argc, char* argv[])
{
printf("Hello Intercom!\n");
IModel* lpModelHDD = new CModelAnalyzeHDD();
IModel* lpModelUSB = new CModelAnalyzeUSB();
IBaseView* lpViewTree = new CBaseViewList();
IBaseView* lpViewList = new CBaseViewTree();
IInterCom::getInstance()->Register(lpModelHDD,lpViewTree);
IInterCom::getInstance()->Register(lpModelHDD,lpViewList);
IInterCom::getInstance()->Register(lpModelHDD,lpModelUSB);
IInterCom::getInstance()->Register(lpModelUSB,lpViewTree);
IInterCom::getInstance()->Register(lpModelUSB,lpViewList);
IInterCom::getInstance()->Register(lpModelUSB,lpModelHDD);
lpModelHDD->analyze();
printf("\n======================");
lpModelUSB->analyze();
printf("\n======================");
IInterCom::getInstance()->Register(lpViewTree,lpViewList);
IInterCom::getInstance()->Register(lpViewTree,lpModelUSB);
IInterCom::getInstance()->Register(lpViewTree,lpModelHDD);
((CBaseViewTree*)lpViewTree)->onClick();
printf("\n======================");
IInterCom::getInstance()->Register(lpViewList,lpViewList);
IInterCom::getInstance()->Register(lpViewList,lpModelUSB);
IInterCom::getInstance()->Register(lpViewList,lpModelHDD);
((CBaseViewList*)lpViewList)->onClick();
printf("\n======================");
delete lpViewList;
delete lpViewTree;
delete lpModelHDD;
delete lpModelUSB;
IInterCom::releaseInstance();
getch();
return 0;
}
Intercom Pattern Class - IInterCom.h
/===============INTERCOM CLASS=================================/
#ifndef _IInterCom_H_
#define _IInterCom_H_
#include <VECTOR />
using namespace std;
struct BaseMessage
{
public:
int Progress;
int MsgType;
int NoOfDevice;
char* Data;
};
class Observer;
class Subject;
class Message
{
public:
Message(Subject* sub,BaseMessage* msgData){subject = sub;Msg = msgData;};
Subject* subject;
BaseMessage* Msg;};
class Observer
{
public:
virtual int onMessage(const Message& m){return 0;};
virtual int onGoodBye(){return 0;};
};
class Subject : public Observer{
public:
vector<Observer*>mObservers;
};
class IInterCom
{
public:
IInterCom();
virtual ~IInterCom();
static IInterCom* getInstance();
static void releaseInstance();
void Register(Subject* subject,Observer* observer);
int Revoke(Subject* subject,Observer* observer);
int RevokeAll(Subject* subject);
int Dispatch(const Message& message);
protected:
int IsSubjectRegistered(Subject* subject);
int IsObserverRegistered(Subject* subject,Observer* observer);
private:
static IInterCom* mpInstance;
vector<Subject*>mSubjects;
};
Intercom Pattern Class - IInterCom.cpp
#include "stdafx.h"
#include "IInterCom.h"
IInterCom* IInterCom::mpInstance = NULL;
IInterCom::IInterCom()
{
mSubjects.clear();
}
IInterCom::~IInterCom()
{
}
IInterCom* IInterCom::getInstance()
{
if (NULL == mpInstance)
{
mpInstance = new IInterCom;
}
return mpInstance;
}
void IInterCom::releaseInstance()
{
if (NULL != mpInstance)
{
delete mpInstance;
mpInstance = NULL;
}
}
void IInterCom::Register(Subject* subject,Observer* observer)
{
if (IsSubjectRegistered(subject) < 0 )
{
mSubjects.push_back(subject);
}
subject->mObservers.push_back(observer);
}
int IInterCom::Revoke(Subject* subject,Observer* observer)
{
Observer* pObserver = NULL;
int liSize = subject->mObservers.size();
for (int i = 0; i< liSize; i++)
{
if (observer == subject->mObservers.at(i))
{
pObserver = subject->mObservers.at(i);
if (pObserver)
{
pObserver->onGoodBye();
}
subject->mObservers.erase(&pObserver);
}
}
return 0;
}
int IInterCom::RevokeAll(Subject* subject)
{
Observer* pObserver = NULL;
int liSize = subject->mObservers.size();
int i = 0;
for (int i = 0; i< liSize; i++)
{
pObserver = subject->mObservers.at(i);
if (pObserver)
{
pObserver->onGoodBye();
}
}
subject->mObservers.clear();
return 0;
}
int IInterCom::Dispatch(const Message& message)
{
Subject* pSubject = NULL;
Observer* pObserver = NULL;
int liSize = mSubjects.size();
for (int i = 0; i< liSize; i++)
{
pSubject = mSubjects.at(i);
if (pSubject == message.subject)
{
int liObservers = pSubject->mObservers.size();
for (int j = 0; j< liObservers; j++)
{
pObserver = pSubject->mObservers.at(j);
pObserver->onMessage(message);
}
}
}
return 0;
}
int IInterCom::IsSubjectRegistered(Subject* subject)
{
int liSize = mSubjects.size();
for (int i = 0; i< liSize; i++)
{
if (subject == mSubjects.at(i))
{
return i;
}
}
return -1;
}
int IInterCom::IsObserverRegistered(Subject* subject,Observer* observer)
{
Observer* pObserver = NULL;
int liSize = subject->mObservers.no();
int i = 0;
for ( i = 0; i< liSize; i++)
{
pObserver = subject->mObservers.at(i);
if (observer == pObserver)
{
return i;
}
}
return -1;
}
/=======================END INTERCOMCLASS==============================/
Model Class
/======================MODEL CLASS=====================================/
#ifndef _IModel_H_
#define _IModel_H_
#include "IInterCom.h"
class IModel : public Subject
{
public:
IModel();
virtual ~IModel();
virtual void analyze() = 0;
};
class CModelAnalyzeHDD : public IModel
{
public:
CModelAnalyzeHDD(){}
virtual ~CModelAnalyzeHDD(){}
virtual int onMessage(const Message& m);
virtual void analyze();
};
class CModelAnalyzeUSB : public IModel
{
public:
CModelAnalyzeUSB(){}
virtual ~CModelAnalyzeUSB(){}
virtual int onMessage(const Message& m);
virtual void analyze();
};
#endif
--------------------------------------------------------------------
#include "stdafx.h"
#include "IModel.h"
#include "IBaseView.h"
IModel::IModel()
{
}
IModel::~IModel()
{
}
int CModelAnalyzeHDD::onMessage(const Message& m)
{
if (typeid(*m.subject) == typeid(CBaseViewList))
{
printf("\nSubject: CBaseViewList--------Observer:CModelAnalyzeHDD");
}
else if (typeid(*m.subject) == typeid(CBaseViewTree))
{
printf("\nSubject: CBaseViewTree--------Observer:CModelAnalyzeHDD");
}
else if (typeid(*m.subject) == typeid(CModelAnalyzeUSB))
{
printf("\nSubject: CModelAnalyzeUSB--------Observer:CModelAnalyzeHDD");
}
return 0;
}
void CModelAnalyzeHDD::analyze()
{
BaseMessage msg;
msg.Data = "HDDAnalyze";
msg.NoOfDevice = 3;
Message m(this,&msg);
IInterCom::getInstance()->Dispatch(m);
}
int CModelAnalyzeUSB::onMessage(const Message& m)
{
if (typeid(*m.subject) == typeid(CBaseViewList))
{
printf("\nSubject: CBaseViewList--------Observer:CModelAnalyzeUSB");
}
else if (typeid(*m.subject) == typeid(CBaseViewTree))
{
printf("\nSubject: CBaseViewTree--------Observer:CModelAnalyzeUSB");
}
else if (typeid(*m.subject) == typeid(CModelAnalyzeHDD))
{
printf("\nSubject: CModelAnalyzeHDD--------Observer:CModelAnalyzeUSB");
}
return 0;
}
void CModelAnalyzeUSB::analyze()
{
BaseMessage msg;
msg.Data = "UsbAnalyze";
msg.NoOfDevice = 2;
Message m(this,&msg);
IInterCom::getInstance()->Dispatch(m);
}
View Class
/=========================================VIEW CLASS==========================/
#ifndef _IBaseView_H_
#define _IBaseView_H_
#include "IInterCom.h"
class IBaseView : public Subject
{
public:
IBaseView();
virtual ~IBaseView();
};
class CBaseViewTree : public IBaseView
{
public:
CBaseViewTree(){};
virtual ~CBaseViewTree(){};
virtual int onMessage(const Message& m);
void onClick();
};
class CBaseViewList : public IBaseView
{
public:
CBaseViewList(){};
virtual ~CBaseViewList(){};
virtual int onMessage(const Message& m);
void onClick();
};
#endif
------------------------------------------------------------------------------------
#include "stdafx.h"
#include "IBaseView.h"
#include "IModel.h"
IBaseView::IBaseView()
{
}
IBaseView::~IBaseView()
{
}
void CBaseViewTree::onClick()
{
BaseMessage msg;
msg.Data = "Driveletter";
Message m(this,&msg);
IInterCom::getInstance()->Dispatch(m);
}
int CBaseViewTree::onMessage(const Message& m)
{
if (typeid(*m.subject) == typeid(CBaseViewList))
{
printf("\nSubject: CBaseViewList--------Observer:CBaseViewTree");
}
else if (typeid(*m.subject) == typeid(CModelAnalyzeHDD))
{
printf("\nSubject: CModelAnalyzeHDD--------Observer:CBaseViewTree");
}
else if (typeid(*m.subject) == typeid(CModelAnalyzeUSB))
{
printf("\nSubject: CModelAnalyzeUSB--------Observer:CBaseViewTree");
}
return 0;
}
int CBaseViewList::onMessage(const Message& m)
{
if (typeid(*m.subject) == typeid(CBaseViewTree))
{
printf("\nSubject: CBaseViewTree--------Observer:CBaseViewList");
}
else if (typeid(*m.subject) == typeid(CModelAnalyzeHDD))
{
printf("\nSubject: CModelAnalyzeHDD--------Observer:CBaseViewList");
}
else if (typeid(*m.subject) == typeid(CModelAnalyzeUSB))
{
printf("\nSubject: CModelAnalyzeUSB--------Observer:CBaseViewList");
}
return 0;
}
void CBaseViewList::onClick()
{
BaseMessage msg;
msg.Data = "Driveletter";
Message m(this,&msg);
IInterCom::getInstance()->Dispatch(m);
}
/====================================================================
Typical Usages
The typical usages of the Intercom pattern are as follows:
- Listen for an external event (such as a user action)
- See Event-driven programming
- Listen for changes of the value of an object property
In a mailing list, where every time an event happens (a new product, a gathering, etc.), a message is sent to the people subscribed to the list. The main reason for using this pattern is its simplicity and dynamic change of subject and observer. The Intercom pattern is also very often associated with the model-view-controller (MVC) paradigm. In MVC, the Intercom pattern is used to create a loose coupling between the model and the view. Typically, a modification in the model triggers the notification of model observers which are actually the views.