Composition of C + + design patterns (structural)

Posted by mentalfloss on Sun, 12 Jan 2020 15:51:56 +0100

 

For the tree structure, when a method of a container object (such as a folder) is called, the entire tree structure will be traversed, the member objects (such as container objects or leaf objects, such as subfolders and files) containing the method will be found and called for execution. (recursive call)

Because of the differences in functions between container objects and leaf objects, container objects and leaf objects must be treated differently in the client code that uses these objects. In fact, in most cases, the client wants to handle them consistently, because the different treatment of these objects will make the program very complex.

The combination pattern describes how to recursively combine the container object and the leaf object, so that the user can treat the container object and the leaf object uniformly without distinguishing them when using, which is the pattern motivation of the combination pattern.

Schema definition

Composite pattern: combine multiple objects to form a tree structure to represent the "whole part" structure hierarchy. The combination mode is consistent for the use of single objects (i.e. leaf objects) and combined objects (i.e. container objects).

Composite pattern, also known as "part whole" pattern, belongs to the structure pattern of objects. It organizes objects into a tree structure and can be used to describe the relationship between the whole and the part.

Classification of combination patterns

1) Define the method to manage child elements in Composite Class.
2) Define the method to manage child elements in Component Interface, so the Leaf class needs to implement these methods null.

Applicability

1) . you want to represent the part whole hierarchy of objects

2) . you want users to ignore the difference between composite objects and single objects, and users will use all objects in the composite structure uniformly.

Mode advantages:

1) The basic object of the class hierarchy containing the basic object and the composite object can be combined into a more complex composite object, and the composite object can be combined again, so it can be recursively continued. In customer code, composite objects can be used wherever basic objects are used.
2) • simplify customer code customers can use composite structures and individual objects consistently. Usually users don't know (and don't care) whether they are dealing with a leaf node or a composite component. This simplifies the client code because there is no need to write functions full of selection statements in the classes that define the composition.
3) • make it easier to add new types of components. The newly defined Composite or Leaf subclass automatically works with the existing structure and customer code, and the customer program does not need to change due to the new Component class.
4) • making your design more generic and easy to add new components can also cause problems, which are that it's hard to limit the components in your portfolio. Sometimes you want a combination to have only certain components. When using Composite, you can't rely on the type system to impose these constraints, you have to check at run time.

ULM diagram

 

The composite pattern consists of the following roles:

• Component: abstract Component

• Leaf: Leaf component

• Composite: container components

• Client: customer class

Example

Company:

A group company, which has a parent company and many subsidiaries. No matter the parent company or the subsidiary company, they have their own direct financial department, human resources department, sales department, etc. For the parent company, whether it is a subsidiary, or the financial department and human resources department directly under it, are all its departments. The Department topology of the whole company is a tree structure.

The following is a UML diagram of the composite pattern. As you can see from the figure, two classes, FinanceDepartment and HRDepartment, are leaf nodes, so no add function is defined. The ConcreteCompany class can be used as an intermediate node, so there can be added functions. So how to add it? This class defines a linked list to hold the added elements.

The implementation code is as follows:

#include <iostream>
#include <list>
#include <memory>
#include <utility>
#include <cstddef>

using namespace std;

class Company
{
public:
	Company(string name) { m_name = name; }
	virtual ~Company() {}
	virtual void Add(std::unique_ptr<Company>) {}//In this case, the default implementation is null function, and the implementation in leaf node is not null
	virtual void Show(int depth) {} // In this case, the default implementation is null function, and the implementation in leaf node is not null
protected:
	string m_name;
};

//Specific company
class ConcreteCompany : public Company
{
public:
	ConcreteCompany(string name) : Company(name) {}
	virtual ~ConcreteCompany() 
    {
		for (auto& company : m_listCompany)
		{
		     company.reset(nullptr);
		}
	}
	void Add(std::unique_ptr<Company> pCom) { m_listCompany.push_back(std::move(pCom)); } //Located in the middle of the tree, you can add subtrees
	void Show(int depth)
	{
		for (int i = 0; i < depth; i++)
			cout << "-";
		cout << m_name << endl;
		auto iter = m_listCompany.begin();
		for (; iter != m_listCompany.end(); iter++) //Show lower nodes
			(*iter)->Show(depth + 2);
	}
private:
	list<std::unique_ptr<Company>> m_listCompany;
};

//Specific department, finance department
class FinanceDepartment : public Company
{
public:
	FinanceDepartment(string name) :Company(name) {}
	virtual ~FinanceDepartment() {}
	virtual void Show(int depth) //Just show, add functions infinitely, because it is already a leaf node
	{
		for (int i = 0; i < depth; i++)
			cout << "-";
		cout << m_name << endl;
	}
};

//Specific department, human resources department
class HRDepartment :public Company
{
public:
	HRDepartment(string name) :Company(name) {}
	virtual ~HRDepartment() {}
	virtual void Show(int depth) //Just show, add functions infinitely, because it is already a leaf node
	{
		for (int i = 0; i < depth; i++)
			cout << "-";
		cout << m_name << endl;
	}
};

int main()
{
	auto root = std::make_unique<ConcreteCompany>("Headquarters");
	auto leaf1 = std::make_unique < FinanceDepartment>("Finance Department of head office");
	auto leaf2 = std::make_unique < HRDepartment>("Head office human resources department");
	root->Add(std::move(leaf1));
	root->Add(std::move(leaf2));

	//Branch Office
	auto mid1 = std::make_unique < ConcreteCompany>("Hangzhou branch ");
	auto leaf3 = std::make_unique < FinanceDepartment>("Hangzhou Branch Finance Department");
	auto leaf4 = std::make_unique < HRDepartment>("Human Resources Department of Hangzhou Branch");
	mid1->Add(std::move(leaf3));
	mid1->Add(std::move(leaf4));
	root->Add(std::move(mid1));
	//Branch Office
	auto mid2 = std::make_unique < ConcreteCompany>("Shanghai Branch");
	auto leaf5 = std::make_unique < FinanceDepartment>("Finance Department of Shanghai Branch");
	auto leaf6 = std::make_unique < HRDepartment>("Human Resources Department of Shanghai Branch");
	mid2->Add(std::move(leaf5));
	mid2->Add(std::move(leaf6));
	root->Add(std::move(mid2));
	root->Show(0);

	
	return 0;
}

The operation results are as follows:

 

236 original articles published, 35 praised, 240000 visitors+
Private letter follow