Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / WinMobile

Intercom Pattern

2.16/5 (24 votes)
22 May 2008CPOL2 min read 2   106  
Defines many to many relationship between different types of classes.
Image 1

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

C++
=====================================================
#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();

    //REGISTER FOR NOTIFICATION FROM MODEL CHANGE...
    IInterCom::getInstance()->Register(lpModelHDD,lpViewTree);
    IInterCom::getInstance()->Register(lpModelHDD,lpViewList);
    //NOTIFY ITS RELATIVE MODEL...
    IInterCom::getInstance()->Register(lpModelHDD,lpModelUSB);
    //
    IInterCom::getInstance()->Register(lpModelUSB,lpViewTree);
    IInterCom::getInstance()->Register(lpModelUSB,lpViewList);
    //NOTIFY ITS RELATIVE MODEL...
    IInterCom::getInstance()->Register(lpModelUSB,lpModelHDD);

    lpModelHDD->analyze();
    printf("\n======================");
    lpModelUSB->analyze();
    printf("\n======================");
    //NOTIFY ITS RELATIVE VIEW...AS WELL AS MODEL
    IInterCom::getInstance()->Register(lpViewTree,lpViewList);
    IInterCom::getInstance()->Register(lpViewTree,lpModelUSB);
    IInterCom::getInstance()->Register(lpViewTree,lpModelHDD);

    ((CBaseViewTree*)lpViewTree)->onClick();
    printf("\n======================");

    //NOTIFY ITS RELATIVE VIEW...AS WELL AS MODEL
    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

C++
/===============INTERCOM CLASS=================================/
//######################################################################
//# FILENAME: IInterCom.h
//#
//# DESCRIPTION: FOR MESSAGE PASING AMONG MANY OF CLASSES.
//# USER CAN USE DIFFERENT TYPES OF MESSAGE BUT ONLY 2 onMessage,onGoodBye
//# ARE MORE ACCEPTABLE. INTERNALLY USED <OBSERVER /> PATTERN
//# AUTHOR:        Mohammad Saiful Alam (Jewel)
//# POSITION:    Senior Software Engineer
//# E-MAIL:        saiful.alam@ bjitgroup.com
//# CREATE DATE: 2008/02/1
//#
//# Copyright (c) 2007 BJIT Ltd.
//######################################################################

#ifndef _IInterCom_H_
#define _IInterCom_H_

//--------------------------------------------------------------------------------
//EXPOSE SOME EXAMPLE MESSAGE...
//USEER CAN DEFINE ANY TYPES OF MESSAGE
//THESE MESSAGE HAS TO BE USED BY Message class...

#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;//ALLOW DIFFERENT TYPES OF MESSAGES...
};

class Observer
{
public:
    virtual int onMessage(const Message& m){return 0;};
    virtual int onGoodBye(){return 0;};
};
//
class Subject : public Observer//ALLOW DIFFERENT TYPES OF SUBJECTS......
{
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

C++
//######################################################################
//# FILENAME: IInterCom.cpp
//#
//# DESCRIPTION:
//#
//#
//# AUTHOR:      Mohammad Saiful Alam (Jewel)
//# POSITION:    Senior Software Engineer
//# E-MAIL:      saiful.alam@ bjitgroup.com
//# CREATE DATE: 2008/02/1
//#
//# Copyright (c) 2007 BJIT Ltd.
//######################################################################

#include "stdafx.h"
#include "IInterCom.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

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

C++
/======================MODEL CLASS=====================================/

// IModel.h: interface for the IModel class.
//
//////////////////////////////////////////////////////////////////////
#ifndef _IModel_H_
#define _IModel_H_

#include "IInterCom.h"

//NEEDS TO COMMUNICATE WITH OTHERS
//MAY BE VIEW, MAY BE MODEL ETC...

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

--------------------------------------------------------------------
// IModel.cpp: implementation of the IModel class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "IModel.h"
#include "IBaseView.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

IModel::IModel()
{

}

IModel::~IModel()
{

}
//////////////////////////////////////////////////////////////////////////
//CModelAnalyzeHDD
//////////////////////////////////////////////////////////////////////////
int CModelAnalyzeHDD::onMessage(const Message& m)
{
    if (typeid(*m.subject) == typeid(CBaseViewList))
    {
        //Message from CBaseViewList
        printf("\nSubject: CBaseViewList--------Observer:CModelAnalyzeHDD");
    }
    else if (typeid(*m.subject) == typeid(CBaseViewTree))
    {
        //Message from CModelAnalyzeHDD
        printf("\nSubject: CBaseViewTree--------Observer:CModelAnalyzeHDD");
    }
    else if (typeid(*m.subject) == typeid(CModelAnalyzeUSB))
    {
        //Message from CModelAnalyzeUSB
        printf("\nSubject: CModelAnalyzeUSB--------Observer:CModelAnalyzeHDD");
    }
    return 0;
}
void CModelAnalyzeHDD::analyze()
{
    BaseMessage msg;
    msg.Data = "HDDAnalyze";
    msg.NoOfDevice = 3;
      Message m(this,&msg);
    //NOTIFY ITS REGISTERED OBSERVER...
    //THIS PART IS DONE BY INTERCOM...
    IInterCom::getInstance()->Dispatch(m);
}
//////////////////////////////////////////////////////////////////////////
//CModelAnalyzeUSB
//////////////////////////////////////////////////////////////////////////
int CModelAnalyzeUSB::onMessage(const Message& m)
{
    if (typeid(*m.subject) == typeid(CBaseViewList))
    {
        //Message from CBaseViewList
        printf("\nSubject: CBaseViewList--------Observer:CModelAnalyzeUSB");
    }
    else if (typeid(*m.subject) == typeid(CBaseViewTree))
    {
        //Message from CModelAnalyzeHDD
        printf("\nSubject: CBaseViewTree--------Observer:CModelAnalyzeUSB");
    }
    else if (typeid(*m.subject) == typeid(CModelAnalyzeHDD))
    {
        //Message from CModelAnalyzeUSB
        printf("\nSubject: CModelAnalyzeHDD--------Observer:CModelAnalyzeUSB");
    }
    return 0;
}
void CModelAnalyzeUSB::analyze()
{
    BaseMessage msg;
    msg.Data = "UsbAnalyze";
    msg.NoOfDevice = 2;
      Message m(this,&msg);
    //NOTIFY ITS REGISTERED OBSERVER...
    //THIS PART IS DONE BY INTERCOM...
    IInterCom::getInstance()->Dispatch(m);

}

View Class

C++
/=========================================VIEW CLASS==========================/
// IBaseView.h: interface for the IBaseView 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

------------------------------------------------------------------------------------
// IBaseView.cpp: implementation of the IBaseView class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "IBaseView.h"
#include "IModel.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

IBaseView::IBaseView()
{

}

IBaseView::~IBaseView()
{

}
//
void CBaseViewTree::onClick()
{
    BaseMessage msg;
    msg.Data = "Driveletter";
      Message m(this,&msg);
    //NOTIFY ITS REGISTERED OBSERVER...
    //THIS PART IS DONE BY INTERCOM...
    IInterCom::getInstance()->Dispatch(m);
}
//////////////////////////////////////////////////////////////////////////
//CBaseViewTree
//////////////////////////////////////////////////////////////////////////
int CBaseViewTree::onMessage(const Message& m)
{
    if (typeid(*m.subject) == typeid(CBaseViewList))
    {
        //Message from CBaseViewList
        printf("\nSubject: CBaseViewList--------Observer:CBaseViewTree");
    }
    else if (typeid(*m.subject) == typeid(CModelAnalyzeHDD))
    {
        //Message from CModelAnalyzeHDD
        printf("\nSubject: CModelAnalyzeHDD--------Observer:CBaseViewTree");
    }
    else if (typeid(*m.subject) == typeid(CModelAnalyzeUSB))
    {
        //Message from CModelAnalyzeUSB
        printf("\nSubject: CModelAnalyzeUSB--------Observer:CBaseViewTree");
    }
    return 0;
}
//////////////////////////////////////////////////////////////////////////
//CBaseViewList
//////////////////////////////////////////////////////////////////////////
int CBaseViewList::onMessage(const Message& m)
{
    if (typeid(*m.subject) == typeid(CBaseViewTree))
    {
        //Message from CBaseViewTree
        printf("\nSubject: CBaseViewTree--------Observer:CBaseViewList");
    }
    else if (typeid(*m.subject) == typeid(CModelAnalyzeHDD))
    {
        //Message from CModelAnalyzeHDD
        printf("\nSubject: CModelAnalyzeHDD--------Observer:CBaseViewList");
    }
    else if (typeid(*m.subject) == typeid(CModelAnalyzeUSB))
    {
        //Message from CModelAnalyzeUSB
        printf("\nSubject: CModelAnalyzeUSB--------Observer:CBaseViewList");
    }
    return 0;
}
//
void CBaseViewList::onClick()
{
    BaseMessage msg;
    msg.Data = "Driveletter";
      Message m(this,&msg);
    //NOTIFY ITS REGISTERED OBSERVER...
    //THIS PART IS DONE BY INTERCOM...
    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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)