Sunday, May 31, 2009

Observer Pattern in Java

As i was going through the different source code files of the Java Util package, i found the implementation of the Observer Pattern ( see the GoF book for more information on this pattern) in the two classes - namely Observer.java and Observable.java. i would like to throw some lights on these two classes. These two classes can be found in the Java\j2se\src\share\classes\java\util folder of the JDK source code.

But first of all, i need to give you a practical example of why we need observer pattern in the first place.

Suppose, we have a document which can be viewed simultaneously by three different views – say one view represents a line graph chart, another view represents it in a spreadsheet, yet another view represents a pie chart. Now suppose the spreadsheet view makes some modification to the document. If the other two views don't update themselves with this changed state of the document, different views will be in inconsistent states. So we need some mechanism to notify the other two views whenever the spreadsheet view updates the document. This is done through Observer pattern in which whenever the document changes stete, it notifies all of its views. The views in turn updates themselves with the latest data.
The class diagram will look like the following.




And the sequence diagram of this pattern is like this.


What these two diagrams essentially depict is that in the Observer Pattern, we have a Subject, which can attach one or more Observers through its Attach() function. Whenever it changes its state it Notifies all the attached Observers through its Notify function. The observers in turn synchronize their states with that of the Subject through the GetSubjectState function.

Now let me try to dissect the Java observer pattern.

Let us first start with the Observable.java class. As the name suggests it is the class which will implemented functionalities for being observed. Or in other words it is the class which helps in designing the Subject class of the Observer pattern discussion of the GoF book. We need to extend this class to get the Subject class.

Let us try to dissect this class. The following functions are there in this class:

Data Members: It has a vector to hold all the observers that are interested in observing this observable class. It has another boolean data member called "changed" to indicate if anything has changed in the Subject class ( which will be derived from this Observable class).

Constructor : This class has a no argument constructor to construct an empty vector of Observers.

Member Functions :

  • addObserver : To add an observer to its list of Observers.

  • deleteObserver : To delete a particular observer from the list of the observers

  • notifyObservers : there are two overloaded versions of this function. One takes an Object parameter as an argument and the other does not take any argument. The task of this function is to notify all the attached observers when any data of the subject gets changed. To check whether the data is changed it evaluates the boolean "changed" data member. This function also calls the update function of each observer objects to ask them to get in sync with the subject's changed state. The overloaded version that takes an one argument parameter is used to let the observers know about which attribute is changed. And the other version of this function which does not take any argument does not let the observer know about which attribute is changed.
  • deleteObservers : This function removes all the observers attached to this subject.

  • setChanged : This function sets the boolean data member "changed".

  • clearChanged : This function resets the boolean data member "changed".

  • hasChanged : This function helps us to know whether the data of the subject has been changed or not. 

  • countObservers : This function returns the number of observers attached to this subject.
This is all about the Observable class which helps us to define to Subject class.

The Observer.java defines an interface called Observer having just one abstract function called update (Observable o, Object arg). As the name suggests, the Observer class that will implement this interface will override the update function to set the attribute passed as an argument (arg) from the Subject class. This method is called whenever any attribute in the Subject class gets changed.

Now let us try to see an example to understand how this Observer Pattern is used.

Let us first extend the Observable class to create the Subject class.

package com.somitsolutions.training.java.observerpattern;

import java.util.Observable;

public class Subject extends Observable {

private String name;
private float price;

public Subject(String name, float price) {
this.name = name;
this.price = price;
}

public String getName() {
return name;
}
public float getPrice() {
return price;
}
public void setName(String name) {
this.name = name;
setChanged();
notifyObservers(name);
}

public void setPrice(float price) {
this.price = price;
setChanged();
notifyObservers(new Float(price));
}
}

As this is clear from the implementation of the Subject class, that whenever we call the setter function to change the attributes of the Subject's object, we call the notifyObservers and pass that attribute as a parameter.


Now let us see how we create two different observers namely NameObserver and PriceObserver to observe these two attributes of the Subject class.

// An observer of name changes.
package com.somitsolutions.training.java.observerpattern;

import java.util.Observable;
import java.util.Observer;

public class NameObserver implements Observer {

private String name;
public NameObserver() {
name = null;
System.out.println("NameObserver created: Name is " + name);
}
@Override
public void update(Observable o, Object arg) {
// TODO Auto-generated method stub
if (arg instanceof String) {
name = (String)arg;
System.out.println("NameObserver: Name changed to " + name);
}
}
}


// An observer of price changes.
package com.somitsolutions.training.java.observerpattern;

import java.util.Observable;
import java.util.Observer;

public class PriceObserver implements Observer {

private float price; public PriceObserver() {
price = 0;
System.out.println("PriceObserver created: Price is " + price);
}
@Override
public void update(Observable o, Object arg) {
// TODO Auto-generated method stub
if (arg instanceof Float) {
price = ((Float)arg).floatValue();
System.out.println("PriceObserver: Price changed to " + price);
}
}

}

As it has become clear from the above two implementations that the update function actually helps in synchronizing the state of the concrete observers with that of the Subject.

Now the client of the Observer framework will look like the following :

package com.somitsolutions.training.java.observerpattern;

public class Main {

public static void main(String args[]) {

// Create the Subject and Observers.
Subject s = new Subject("Kheer Kadam", 20.5f);

NameObserver nameObs = new NameObserver();
PriceObserver priceObs = new PriceObserver();

// Add those Observers!
s.addObserver(nameObs);
s.addObserver(priceObs);

//Initial Subject States
System.out.println("Initial states of Subject");
System.out.println("Name : " + s.getName());
System.out.println("Price : " + Float.toString(s.getPrice()));

// Make changes to the Subject.
s.setName("Gulabjamun"); // It prints NameObserver: Name changed to Gulabjamun

s.setPrice(15.0f); //It prints PriceObserver: Price changed to 15.0

s.setPrice(30.5f); //It prints PriceObserver: Price changed to 30.5

s.setName("Rasgulla"); // It prints NameObserver: Name changed to Rasgulla
}
}

Hope the above discussion will help people understand of how the Java supports implementing the Observer pattern.

Thursday, March 12, 2009

Bridge Pattern in C++



When I studied almost all of the Gang of Four Design Patterns in 2005 or 2006, I knew only one language: C++.

Now I am proficient in multiple software languages and my viewpoint about Design Patterns has also matured...

So, here we go.

Here's the source code of the Bridge Pattern, the code is extracted from the presentation.

//Coord.h

#ifndef COORD_H

#define COORD_H


struct Coord {

int x, y;

Coord(int x = 0, int y = 0) : x(x), y(y) {}

};


#endif


// Window.h


#ifndef WINDOW_H

#define WINDOW_H


#include "Coord.h"

#include "WindowImp.h"


class Window {

public:

Window();

virtual ~Window();


void GetWindowImp(int typeOfImplementation); // Attaches implementation

void DrawLine(const Coord& begin, const Coord& end);

void DrawRect(const Coord& topLeft, const Coord& bottomRight);


protected:

WindowImp* imp = nullptr;

};


class IconWindow : public Window {

public:

void DrawBorder(const Coord& topLeft, const Coord& bottomRight);

};


class TransientWindow : public Window {

// Can add specific behavior if needed

};


#endif



// Window.cpp


#include "Window.h"

#include "WindowSystemFactory.h"

#include <iostream>


Window::Window() {}


Window::~Window() {

delete imp;

}


void Window::GetWindowImp(int typeOfImplementation) {

imp = WindowSystemFactory::Instance()->MakeWindowImp(typeOfImplementation);

}


void Window::DrawLine(const Coord& begin, const Coord& end) {

if (imp) imp->DeviceLine(begin, end);

}


void Window::DrawRect(const Coord& topLeft, const Coord& bottomRight) {

if (imp) imp->DeviceRect(topLeft, bottomRight);

}


void IconWindow::DrawBorder(const Coord& topLeft, const Coord& bottomRight) {

DrawRect(topLeft, bottomRight); // Uses bridged implementation

}


// WindowImp.h

#ifndef WINDOWIMP_H

#define WINDOWIMP_H


#include "Coord.h"


class WindowImp {

public:

virtual ~WindowImp() = default;

virtual void DeviceLine(const Coord& begin, const Coord& end) = 0;

virtual void DeviceRect(const Coord& topLeft, const Coord& bottomRight) = 0;

};


class XWindowImp : public WindowImp {

public:

void DeviceLine(const Coord& begin, const Coord& end) override;

void DeviceRect(const Coord& topLeft, const Coord& bottomRight) override;

};


class PMWindowImp : public WindowImp {

public:

void DeviceLine(const Coord& begin, const Coord& end) override;

void DeviceRect(const Coord& topLeft, const Coord& bottomRight) override;

};


#endif


// WindowImp.cpp


#include "WindowImp.h"

#include <iostream>


void XWindowImp::DeviceLine(const Coord&, const Coord&) {

std::cout << "XWindow: Drawing Line\n";

}


void XWindowImp::DeviceRect(const Coord&, const Coord&) {

std::cout << "XWindow: Drawing Rectangle\n";

}


void PMWindowImp::DeviceLine(const Coord&, const Coord&) {

std::cout << "PMWindow: Drawing Line\n";

}


void PMWindowImp::DeviceRect(const Coord&, const Coord&) {

std::cout << "PMWindow: Drawing Rectangle\n";

}



// WindowSystemFactory.h

#ifndef WINDOWSYSTEMFACTORY_H

#define WINDOWSYSTEMFACTORY_H


class WindowImp;


enum WindowImplementation {

XWindowImplementation,

PMWindowImplementation

};


class WindowSystemFactory {

public:

static WindowSystemFactory* Instance();

WindowImp* MakeWindowImp(int type);


private:

WindowSystemFactory() = default;

static WindowSystemFactory* instance;

};


#endif


// WindowSystemFactory.cpp

#include "WindowSystemFactory.h"

#include "WindowImp.h"


WindowSystemFactory* WindowSystemFactory::instance = nullptr;


WindowSystemFactory* WindowSystemFactory::Instance() {

if (!instance) {

instance = new WindowSystemFactory();

}

return instance;

}


WindowImp* WindowSystemFactory::MakeWindowImp(int type) {

if (type == XWindowImplementation) return new XWindowImp();

if (type == PMWindowImplementation) return new PMWindowImp();

return nullptr;

}



//============================================================================

// Name : BridgePattern.cpp

// Author : Som

// Version :

// Copyright : som-itsolutions

// Description : Hello World in C++, Ansi-style

//============================================================================


#include "Window.h"

#include "Coord.h"

#include "WindowSystemFactory.h"

#include <iostream>


int main() {

const Coord pt0(1, 2);

const Coord pt1(7, 8);


// X-based Icon Window

IconWindow* xIcon = new IconWindow();

xIcon->GetWindowImp(XWindowImplementation);

xIcon->DrawBorder(pt0, pt1);


// PM-based Transient Window

TransientWindow* pmTransient = new TransientWindow();

pmTransient->GetWindowImp(PMWindowImplementation);

pmTransient->DrawRect(pt0, pt1);


// PM-based Icon Window

IconWindow* pmIcon = new IconWindow();

pmIcon->GetWindowImp(PMWindowImplementation);

pmIcon->DrawLine(pt0, pt1);


delete xIcon;

delete pmTransient;

delete pmIcon;


return 0;

}

Sunday, January 25, 2009

Android Widget - through Java Code

There are two ways to create android resources/view - either through the XML layout or through pure java code. In this article I have tried to implement the android view through the second method - i.e. through Java code. I have implemented a Table Layout and few widgets like static text, edit box and slider bar. There are three sets of all these widgets - namely Red, Green and Blue. These three are the percentage of the RGB color code. For example if we make Red as 100, and Green and Blue as 0, it will paint the background of the device with Red. It has also shown how to create a prompt dialog when you enter a value more than 100 in any of the edit boxes.

The application will look like the following:



The code for this application is as follow -

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class Widget extends Activity implements View.OnClickListener /*, View.OnKeyListener */{
/** Called when the activity is first created. */

private final static int idLayout = 1;
private final static int idTitle = 2;

private final static int idTextRed = 3;
private final static int idTextGreen = 4;
private final static int idTextBlue = 5;

private final static int idEditRedText = 6;
private final static int idEditGreenText = 7;
private final static int idEditBlueText = 8;

private final static int idSeekBarRed = 9;
private final static int idSeekBarGreen = 10;
private final static int idSeekBarBlue =11;

private final static int idButtonOK = 12;

private final static int MaxColorValue = 255;

private int RedProgress = 0;
private int GreenProgress = 0;
private int BlueProgress = 0;

private int RedValue = 0;
private int GreenValue = 0;
private int BlueValue = 0;


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);


setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

TableLayout layout = new TableLayout(this);
layout.setId(idLayout);
layout.setLayoutParams(
new LayoutParams(LayoutParams.FILL_PARENT,android.view.ViewGroup.LayoutParams.FILL_PARENT));
layout.setFocusable(true);

TextView title = new TextView(this);
title.setText(R.string.title);
title.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
//title.s(Alignment.ALIGN_CENTER);
title.setId(idTitle);
layout.addView(title,0);


//For Item 1
TextView ItemRed = new TextView(this);
ItemRed.setFocusable(true);
ItemRed.setText("% RED");
ItemRed.setTextColor(Color.LTGRAY);
ItemRed.setLayoutParams(
new TableLayout.LayoutParams(
TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));

//Give the menu item an ID for tracking reasons.
//The ID is a static int defined locally to the class
ItemRed.setId(idTextRed);
//Add it to our linear layout
layout.addView(ItemRed, 1);

EditText EditTextRed = new EditText(this);
EditTextRed.setFocusable(true);
EditTextRed.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
EditTextRed.setId(idEditRedText);

layout.addView(EditTextRed, 2);

SeekBar SeekBarRed = new SeekBar(this);
SeekBarRed.setFocusable(true);
SeekBarRed.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
SeekBarRed.setMax(MaxColorValue);
SeekBarRed.setId(idSeekBarRed);


layout.addView(SeekBarRed, 3);


//For item 2
TextView ItemGreen = new TextView(this);
ItemGreen.setFocusable(true);
ItemGreen.setText("% GREEN");
ItemGreen.setTextColor(Color.LTGRAY);
ItemGreen.setLayoutParams(
new TableLayout.LayoutParams(
TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));


//Give the menu item an ID for tracking reasons.
//The ID is a static int defined locally to the class
ItemGreen.setId(idTextGreen);
//Add it to our linear layout
layout.addView(ItemGreen, 4);

EditText EditTextGreen = new EditText(this);
EditTextGreen.setFocusable(true);
EditTextGreen.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
EditTextRed.setId(idEditGreenText);

layout.addView(EditTextGreen, 5);

SeekBar SeekBarGreen = new SeekBar(this);
SeekBarGreen.setFocusable(true);
SeekBarGreen.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
SeekBarGreen.setMax(MaxColorValue);
SeekBarGreen.setId(idSeekBarGreen);
layout.addView(SeekBarGreen, 6);


TextView ItemBlue = new TextView(this);
ItemBlue.setFocusable(true);
ItemBlue.setText("% BLUE");
ItemBlue.setTextColor(Color.LTGRAY);
ItemBlue.setLayoutParams(
new TableLayout.LayoutParams(
TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));


//Give the menu item an ID for tracking reasons.
//The ID is a static int defined locally to the class
ItemBlue.setId(idTextBlue);
//Add it to our linear layout
layout.addView(ItemBlue, 7);


EditText EditTextBlue = new EditText(this);
EditTextBlue.setFocusable(true);
EditTextBlue.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
EditTextBlue.setId(idEditBlueText);

layout.addView(EditTextBlue, 8);

SeekBar SeekBarBlue = new SeekBar(this);
SeekBarBlue.setFocusable(true);
SeekBarBlue.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
SeekBarBlue.setMax(MaxColorValue);
SeekBarBlue.setId(idSeekBarBlue);
layout.addView(SeekBarBlue, 9);

Button OKBtn = new Button(this);
OKBtn.setFocusable(true);
OKBtn.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
OKBtn.setId(idButtonOK);
OKBtn.setText("OK");
layout.addView(OKBtn,10);


setContentView(layout);

OKBtn.setOnClickListener(this);

SeekBarRed.setOnSeekBarChangeListener(OnSeekBarProgress);
SeekBarGreen.setOnSeekBarChangeListener(OnSeekBarProgress);
SeekBarBlue.setOnSeekBarChangeListener(OnSeekBarProgress);
}

OnSeekBarChangeListener OnSeekBarProgress =
new OnSeekBarChangeListener() {

public void onProgressChanged(SeekBar s, int progress, boolean touch){

if(touch){
TableLayout layout = (TableLayout)s.getParent();

EditText Red = (EditText)layout.getChildAt(2);
EditText Green = (EditText)layout.getChildAt(5);
EditText Blue = (EditText)layout.getChildAt(8);

if(s.getId()== idSeekBarRed ){
RedProgress = progress;
Red.setText(Integer.toString(RedProgress*100/254));
}

if(s.getId()== idSeekBarGreen ){

GreenProgress = progress;
Green.setText(Integer.toString(GreenProgress*100/254));
}


if(s.getId()== idSeekBarBlue ){

BlueProgress = progress;
Blue.setText(Integer.toString(BlueProgress*100/254));
}

int color = Color.rgb(RedProgress, GreenProgress, BlueProgress);
layout.setBackgroundColor(color);

}
}

public void onStartTrackingTouch(SeekBar s){

}

public void onStopTrackingTouch(SeekBar s){

}
};


public void onClick(View v){

Button b = (Button)v;

if(b.getId() == idButtonOK){

TableLayout layout = (TableLayout)(v.getParent());

EditText Red = (EditText)layout.getChildAt(2);
EditText Green = (EditText)layout.getChildAt(5);
EditText Blue = (EditText)layout.getChildAt(8);

SeekBar SeekBarRed = (SeekBar)layout.getChildAt(3);
SeekBar SeekBarGreen = (SeekBar)layout.getChildAt(6);
SeekBar SeekBarBlue = (SeekBar)layout.getChildAt(9);


String RedText = Red.getText().toString();
String GreenText = Green.getText().toString();
String BlueText = Blue.getText().toString();


if(!("".equals(RedText))) {
try {
RedValue = Integer.parseInt(RedText);
}
catch (NumberFormatException e) {
}
}
else
RedValue = 0;


if(!("".equals(GreenText))) {
try {
GreenValue = Integer.parseInt(GreenText);
}
catch (NumberFormatException e) {
}
}
else
GreenValue = 0;

if(!("".equals(BlueText))) {
try {
BlueValue = Integer.parseInt(BlueText);
}
catch (NumberFormatException e) {
}
}
else
BlueValue = 0;


if( RedValue>=0 && RedValue<=100) {
RedProgress = 254*RedValue/100;
SeekBarRed.setProgress(RedProgress);
}

else {
new AlertDialog.Builder(this)
.setTitle("Alert!")
.setMessage("Please enter a value between 0 and 100 for RED...")
.setNeutralButton("Close", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
// do nothing – it will close on its own
}
})
.show();
}

if( GreenValue>=0 && GreenValue<=100) {
GreenProgress = 254*GreenValue/100;
SeekBarGreen.setProgress(GreenProgress);
}

else {
new AlertDialog.Builder(this)
.setTitle("Alert!")
.setMessage("Please enter a value between 0 and 100 for GREEN...")
.setNeutralButton("Close", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
// do nothing – it will close on its own
}
})
.show();
}

if(BlueValue>=0 && BlueValue<=100) {
BlueProgress = 254*BlueValue/100;
SeekBarBlue.setProgress(BlueProgress);
}

else {
new AlertDialog.Builder(this)
.setTitle("Alert!")
.setMessage("Please enter a value between 0 and 100 for BLUE...")
.setNeutralButton("Close", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
// do nothing – it will close on its own
}
})
.show();
}

int color = Color.rgb(RedProgress, GreenProgress, BlueProgress);
layout.setBackgroundColor(color);

}

};
}


Play around with it.

Feel happy to work in Android...

Thursday, December 4, 2008

Composite Design Pattern


A composite design pattern is a structural pattern in which we compose the whole-part relationship in a symmetric hierarchy. The client of the composite treats all the objects in the same fashion.
The whole concept of this design pattern lies in the fact that we can treat a composite object which consists of several other objects the same way as a leaf object. The client never knows that it is working on an object which has many other objects inside it.


Let us try to understand the composite pattern with an example. Here we have defined a class namely Shape, which is acting as the root of all the objects in the example. We have put all the basic functionalities of a graphical object in this class. These functions are Add (for adding a component), Remove (for removing a component), GetChild (for getting a pointer to a child), GetParentOfComponent (which will return the parent of a component), and Draw (to draw a component).

The class diagram of my solution looks like the following:



/*
 * Shape.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef SHAPE_H_
#define SHAPE_H_

#include 
#include "LeafClassTypeException.h"
using namespace std;

class Shape
{
public:

 Shape();
 virtual ~Shape();

 virtual void Add(unsigned int id)
 {
 throw LeafClassTypeException();
 };
 virtual void Remove(unsigned int id){};
 //leaf classes will not override it..however, it will be overridden by the composite class.
 virtual Shape* GetChild(unsigned int id)
 {
 throw LeafClassTypeException();
 };
 //Using this reference the "Chain of Responsibility" can be implemented
 virtual Shape* GetParentOfComponent()
 {
 return ParentOfComponent;
 };
 virtual void SetParentOfComponent(Shape* s)
 {
 ParentOfComponent = s;
 }
 virtual void Display(){};
 virtual Shape* FindItem(unsigned int id); //implementation afterwards


protected:
 Shape* ParentOfComponent;
 unsigned int resource_id;
};

#endif /* SHAPE_H_ */


/*
 * Shape.cpp
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#include "Shape.h"
#include 
#include "global.h"

Shape::Shape() {
 // TODO Auto-generated constructor stub
}

Shape::~Shape() {
 // TODO Auto-generated destructor stub
}

Shape* Shape::FindItem(unsigned int id)
{
 theIterator = Resource_Map.begin();
 while (theIterator != Resource_Map.end())
  {
  theIterator = Resource_Map.find(id);
  Shape* s = (*theIterator).second;
  theIterator++;
  return s;
  }

 return NULL;
}



Now from the Shape class, we have derived other graphic classes, like Point, Line and Rectangle. Among these classes, class Point is working as an helper class to define classes like Line and Rectangle. We have deduced another class called Picture which is composed of these component classes.

/*
 * Point.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef POINT_H_
#define POINT_H_
#include 
#include "Shape.h"
#include "global.h"
using namespace std;

class Point : public Shape
{
public:
 Point():x_Coord(0),y_Coord(0){}
 Point(int x, int y):x_Coord(x), y_Coord(y){}
 Point(const Point& p)
 {
 x_Coord = p.x_Coord;
 y_Coord = p.y_Coord;
 }
 Point& operator = (const Point& p)
 {
 x_Coord = p.x_Coord;
 y_Coord = p.y_Coord;

 return *this;
 }

 virtual void Display()
 {
 cout<<"X Coordinate is:"<<x_Coord<<endl;
 cout<<"Y Coordinate is:"<<y_Coord<<endl;
 }

 int X_COORD()
 {
 return x_Coord;
 }

 int Y_COORD()
 {
 return y_Coord;
 }

 virtual ~Point()
 {
 }

private:

 int x_Coord;
 int y_Coord;
};

#endif /* POINT_H_ */

/*
 * Line.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef LINE_H_
#define LINE_H_

#include 
#include "Shape.h"
#include "global.h"
using namespace std;


//class Line is working as a leaf class.. Lets implement it as a final class
class Line : public Shape
{
 private:
 //private constructor
  Line(unsigned int id):begin(0,0),end(0,0)
  {
  resource_id = id;
  Resource_Map.insert(theMap::value_type(resource_id,(Shape*)this));
  }
  //private constructor
  Line(unsigned int id, Point a, Point b):begin(a),end(b)
  {
  resource_id = id;
  Resource_Map.insert(theMap::value_type(resource_id,(Shape*)this));
  }
  //private copy constructor
  Line(const Line& in)
  {

  }



 //private assignment operator
  Line& operator=(const Line& in)
  {
   return *this;
  }

 public:

  virtual void Display()
  {
  cout<<"Begining point is:";
  begin.Display();
  cout<<"End Point is:";
  end.Display();
  }
  static Line* CreateLine(unsigned int id, Point a, Point b)
  {
  return new Line(id,a,b);
  }
private:
 virtual ~Line(){}
 Point begin;
 Point end;
};

#endif /* LINE_H_ */

/*
 * Rectangle.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef RECTANGLE_H_
#define RECTANGLE_H_

#include 
#include "Shape.h"
#include "global.h"
using namespace std;

class Rectangle : public Shape
{
private:
//private constructor
 Rectangle(unsigned int id, Point& p, int width, int height)
 {
 top_left = p;
 top_right = Point(p.X_COORD() + width, p.Y_COORD());
 bottom_left = Point(p.X_COORD() , p.Y_COORD() + height);
 bottom_right = Point(p.X_COORD() + width, p.Y_COORD() + height);
 resource_id = id;
 Resource_Map.insert(theMap::value_type(resource_id,(Shape*)this));
 }
 //private copy constructor
 Rectangle(const Rectangle& in)
 {

 }
 //private assignment operator
 Rectangle& operator=(const Rectangle& in)
 {
  return *this;
 }
public:
 static Rectangle* CreateRectange(unsigned int id, Point& p, int width, int height)
 {
 return new Rectangle(id, p, width, height);
 }
 virtual ~Rectangle(){}
 virtual void Display()
 {
 cout<<"The four vertices are:"<<endl;
 cout<<"Top Left :" ;
 top_left.Display();
 cout <<"Top Right :";
 top_right.Display();
 cout<<"Bottom Left :";
 bottom_left.Display();
 cout<<"Bottom Right :";
 bottom_right.Display();
 }
private:

 //Attributes
 Point top_left;
 Point top_right;
 Point bottom_left;
 Point bottom_right;
};

#endif /* RECTANGLE_H_ */

The interesting point here is that, we have tried to implement the leaf classes, namely Line and Rectangle as final classes by making their constructors private and providing static member functions to create them.

The Picture class is composed of these leaf objects (Line and Rectangle).

/*
 * Picture.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef PICTURE_H_
#define PICTURE_H_

#include 
#include 

#include "Shape.h"
#include "global.h"
using namespace std;

class Picture : public Shape
{
public:
 Picture(unsigned int id)
 {
  resource_id = id;
  Resource_Map.insert(theMap::value_type(resource_id,(Shape*)this));
 }
 virtual void Display()
 {
  vector<Shape*>::iterator p = Components.begin();
  while (p != Components.end())
  {
  (*p)->Display();
  p++;
  }
 }
//Adds the component with the resource id equal to the passed parameter
 virtual void Add (unsigned int id)
 {
  Shape* s = FindItem(id);
  Components.push_back(s);
  s->SetParentOfComponent(this);
 }

//removes the component from the list with the resource_id equal
//to the parameter passed
 virtual void Remove(unsigned int id)
 {
  Shape* s = FindItem(id);
  vector<Shape*>::iterator p = Components.begin();
  int pos = 0;
  while (p != Components.end())
  {
   if(Components.at(pos) == s)
    break;
   pos++;
   p++;
  }
  Components.erase(p);
  s->SetParentOfComponent(NULL);
 }


 //will return the chile having the id equal to the passed value.
 virtual Shape* GetChild (unsigned int id)
 {
  return FindItem(id);
 }
 virtual ~Picture()
 {
  vector<Shape*>::iterator p = Components.begin();
  int pos = 0;
  while (p != Components.end())
  {
   delete(Components.at(pos));
   p++;
   pos++;

  }//while
  Components.clear();
 }


private:
 vector<Shape*> Components;

};

#endif /* PICTURE_H_ */

The Shape class is called as the Component class, the Line and Rectangle classes are called the Leaf classes and the Picture class is called the Composite class.

Another interesting part of the example is that here every component is identifiable through its resource id. Whenever we create an object (leaf or composite object), it creates a key pair of the id and the pointer to that object and pushes this key into a MAP, from which we can easily search for that component in later times through its resource id.


There are many issues to consider when implementing the composite pattern.

We have defined one function called GetParentOfComponent. This can be useful to traverse the whole hierarchy of parent-child relationship. We have to make sure that any child can have only a composite object as its parent. We have ensured it by defining an Exception class which will be thrown the moment we want to add a component to a leaf object. The exception class can be defined as follows:

/*
 * LeafClassTypeException.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef LEAFCLASSTYPEEXCEPTION_H_
#define LEAFCLASSTYPEEXCEPTION_H_

#include 

using namespace std;

class LeafClassTypeException
{
public:
void printerrormsg()
{
cout<<"This is a leaf class"<<endl;
}
};

#endif /* LEAFCLASSTYPEEXCEPTION_H_ */

The global data has been defined inside global.h & global.cpp files.

/*
 * global.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef GLOBAL_H_
#define GLOBAL_H_

#include 
#include "Shape.h"
using namespace std;

typedef map <unsigned int, Shape*, less<unsigned int> > theMap;

extern theMap Resource_Map;

extern theMap::iterator theIterator;

#endif /* GLOBAL_H_ */

/*
 * global.cpp
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#include "global.h"

theMap Resource_Map;

theMap::iterator theIterator;


The client class looks like the following:

/*
 * main.cpp
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#include 
#include "LeafClassTypeException.h"
#include "Point.h"
#include "Line.h"
#include "Rectangle.h"
#include "Picture.h"

using namespace std;

const int  ID_LINE1 = 1;
const int ID_LINE2 = 2;
const int ID_LINE3 = 3;
const int ID_RECTANGLE1 = 4;
const int ID_PICTURE = 5;

int main()
{
 Point p1(10,20);
 Point p2(30,40);
 Point p3(50,60);
 Point p4(70,80);
 Point p5(100,110);
 Point p6(150,200);
 Line* l1 = Line::CreateLine(ID_LINE1,p1,p2);
 try
 {
 l1->Add(0);
 }
 catch(LeafClassTypeException& e)
 {
 e.printerrormsg();
 }
 Line* l2 = Line::CreateLine(ID_LINE2,p3,p4);
 Line* l3 = Line::CreateLine(ID_LINE3,p5,p6);
 Rectangle* r1 = Rectangle::CreateRectange(ID_RECTANGLE1, p1, 50,25);
 Shape* p = new Picture(ID_PICTURE);
 p->Add(ID_LINE1);
 p->Add(ID_LINE2);
 p->Add(ID_LINE3);
 p->Add(ID_RECTANGLE1);
 (p->GetChild(ID_RECTANGLE1))->Display();
 p->Remove(ID_RECTANGLE1);
 p->Display();
 cout<<p<<endl;
 cout<<l1->GetParentOfComponent()<<endl;

 delete p;

 return 0;
}

It should be noted that the functions like Add and Remove have been defined in the root class. Although for leaf classes, it does not do any meaningful things except throwing an exception, but it gives us transparency, because we can treat all components uniformly.

If we define these functions at the composite class level, then it would give the safety, because any attempt to Add or Remove from the leaf classes would give compile time error, but we would loose the transparency. The composite and the leaf classes will have different interfaces in this case.

The main participants in this design pattern are

Component (Shape) : It basically works as an abstract class which provides a common interface which will be used by the client to treat different classes uniformly. The common functionalities (e.g. Display) have been defined here. Other functionalities like Add, Remove, etc have been put in this class to maximize the role of this interface. The default behavior for Add and Remove has been implemented in such a fashion that for a leaf class, these functions will throw exceptions.
Leaf (Line, Rectangle, etc) : It represents a leaf objects in the composition. Leaf objects cannot have any children.
Composite (Picture): It stores child components.

Client: It manipulates the objects through the common interface exposed by the Component class.