Task Grouping Using Composite Design Pattern

Many times we need to perform certain tasks and also group them.

 
[showads ad=inside_post]

These tasks can be,

  • Executing commands on console.

  • Performing some SVN operation.

  • Performing any thing specific to our project.

  • Etc.

Common things in all these tasks can be,

  • Every task need to be executed.

  • Every task returns its log.

  • Every task need to record execution time.

Now what if we want to group this task i.e, combine some of the tasks to create a bigger Grouped Task.

 

Then it will be a perfect example of Composite Design Pattern,

 

Intent of Composite Design Pattern:

Compose objects into tree structures to represent whole-part hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

 

For other modules all tasks has same kind of properties i.e it can execute and returns log, even if its a singletask or a group of tasks. External entities act on all tasks uniformly.

 

Task Group

It has the same common properties like,

 

  • It needs to be executed : It executes all the tasks it contains.

  • It returns its log : It returns the combined logs of all the tasks it contains.

  • It needs to record execution time : It returns the total time taken by all the tasks it contains.

 

A Group Task example can be,

Task Group 1:

              Display Task 1
              Task Group

                             Display Task 2

                              SVN Task

Task Hierarchy ,

 

RunnableTask
Task Grouping Class Diagram

 

A Task Group can contains other task groups too.

 

For external world its every task is a Runnable Task only. Other entities doesn’t know while they are executing a leaf kind of task or a composite kind of task. Thus this composition will be hidden from outside world.

 

Base Class : RunnableTask

class RunnableTask
{
	protected:
		TASK_STATUS m_taskStatus;
		std::string m_name;
	public:
		RunnableTask(std::string name)
		{
			m_taskStatus = NOT_STARTED;
			m_name = name;
		}

		TASK_STATUS getTaskStatus()
		{
			return m_taskStatus;
		}
		std::string getTaskStatusString()
		{
			if(m_taskStatus == NOT_STARTED)
				return "NOT STARTED";
			else if(m_taskStatus == IN_PROGRESS)
				return "IN_PROGRESS";
			else if(m_taskStatus == FINISHED)
				return "FINISHED";
		}
		virtual void execute() = 0;
		virtual std::string getTaskLog() = 0;
		virtual ~RunnableTask(){}

};

TaskGroup class : Non-Leaf Node in Composite Design.

class TaskGroup : public RunnableTask
{
	std::vector<RunnableTask *> listOfRunnableTasks;
	public:
	TaskGroup(std::string name) : RunnableTask(name)
	{}
	void execute()
	{
		m_taskStatus = IN_PROGRESS;
		for(int i = 0; i < listOfRunnableTasks.size(); i++)
		{
			listOfRunnableTasks[i]->execute();
		}
		m_taskStatus = FINISHED;
	}
	std::string getTaskLog()
	{
		std::string log = "TaskGroup :: " + m_name + " ## State :: " + getTaskStatusString() + "\n\n";
		log += "Sub Tasks :: Start\n";
		for(int i = 0; i < listOfRunnableTasks.size(); i++)
		{
			log = log + listOfRunnableTasks[i]->getTaskLog();
		}
		log += "Sub Tasks :: End\n\n";
		return log;
	}
	void addRunnableTask(RunnableTask * pTask)
	{
		listOfRunnableTasks.push_back(pTask);
	}

};

DiplayTask class : Leaf Node in Composite Design.

class DisplayTask : public RunnableTask
{
	public:
	DisplayTask(std::string name) : RunnableTask(name)
	{}
	void execute()
	{
		m_taskStatus = IN_PROGRESS;
		std::cout<<"Display Task Executed\n";
		m_taskStatus = FINISHED;
	}
	std::string getTaskLog()
	{
		std::string log = "DisplayTask :: " + m_name + " ## State :: " + getTaskStatusString() + "\n";
		return log;
	}

};

SVNTask class : Leaf Node in Composite Design.

class SVNTask : public RunnableTask
{
	public:
	SVNTask(std::string name) : RunnableTask(name)
	{}
	void execute()
	{
		m_taskStatus = IN_PROGRESS;
		std::cout<<"Some SVN Task Executed\n";
		m_taskStatus = FINISHED;
	}
	std::string getTaskLog()
	{
		std::string log = "SVNTask :: " + m_name + " ## State :: " + getTaskStatusString() + "\n";
		return log;
	}

};

Usage Details,

typedef enum TASK_STATUS
{
	NOT_STARTED = 0,
	IN_PROGRESS,
	FINISHED,
}TASK_STATUS;

int main()
{
	RunnableTask * pDisptask_1 = new DisplayTask("Sub Task 1");
	RunnableTask * pDisptask_2 = new DisplayTask("Sub Task 2");
	RunnableTask * pSvntask = new SVNTask("Sub Task 3");

	RunnableTask * pTaskGroup_1 = new TaskGroup("Task Group 1");
	pTaskGroup_1->addRunnableTask(pDisptask_1);

	RunnableTask * pTaskGroup_2 = new TaskGroup("Task Group 2");
	pTaskGroup_2->addRunnableTask(pDisptask_2);
	pTaskGroup_2->addRunnableTask(pSvntask);

	pTaskGroup_1->addRunnableTask(pTaskGroup_2);

	std::cout<<pTaskGroup_1->getTaskLog();
	pTaskGroup_1->execute();
	std::cout<<pTaskGroup_1->getTaskLog();

	delete pDisptask_1;
	delete pDisptask_2;
	delete pSvntask;
	delete pTaskGroup_1;
	delete pTaskGroup_2;

	return 0;
}

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top