Composite Pattern

 Introduction:

Composite pattern is a structural design pattern that lets you compose objects into tree structures and then work with these structures as if they were individual objects.

Example, 

Print the file names in the given directory. The given directory contains files and other folders as well. Application has to go through the folders inside the given directory and print the file names also folder name as well. 
The direct approach is define two classes File, Folder, and define the method to print the name. In Folder class, we should have extra implementation to check whether its a file or folder. If its a folder, then go through the files and folders inside and continue further to print names. 

Composite pattern defines the common interface to deal with both file and folder which declares the method to print the name of the file and folder. The benefit of this approach is that we no need to care about the concrete classes. We can treat file and folder as same through the common interface.

When to use, 

  • Use composite pattern when you want to implement a tree like object structure
  • Use when you want client to work with both simple and complex elements uniformly.

How to use, 

Composite pattern has the four participants.

1. Component  -  Component is a interface class .It declares the method which describes the operation that is common for both simple and complex elements of the tree. 

2. Leaf  -  Leaf is the primitive element of the composition (or) base element of the tree. It doesn't have sub elements. Mostly leaf elements ended up doing most of the work.

3. Composite   -  Composite or container is a element that has sub elements(children ).  Composite element doesn't know about the concrete classes of its children. It work with the children through the common interface of the component class. Upon receiving the request, composite delegates the work to the sub elements, process intermediate results, and result the complete result to the client. 

4. Client    - Client work all the elements through the Component interface. As a result, client can work in the same way with simple and complex elements of the tree.

UML diagram:

Structure of the Composite design pattern

























Implementation:

Application to print all the file names, folder names under the given directory.

Sourcecode: https://github.com/krishnaKSA/design_patterns_cplusplus/blob/main/CompositePattern/CompositePattern.hpp

Class diagram:

























Component Interface class:

//Component class
    class AbstractFile
    {
        public:
        virtual void listFiles() = 0;
    };

Leaf class:

    //Leaf class
    class File :  public AbstractFile
    {
        private:
        string fileName;
        public:
        File(string name)
        {
            fileName  = name;
        }
        void listFiles() override
        {
            cout<<fileName<<endl;
        }
    };

Composite class:

    //Composite class
    class Directory :  public AbstractFile
    {
        private:
        string fileName;
        vector<AbstractFile*> fileList;
        public:
        Directory(string name)
        {
            fileName  = name;
            fileList = vector<AbstractFile*>();
        }
        void add(AbstractFile* obj)
        {
            fileList.push_back(obj);
        }
        void listFiles() override
        {
            cout<<fileName<<endl;
            for(AbstractFile* obj:fileList)
            {
                obj->listFiles();
            }            
        }
    };

Client code:

    void testClientCode()
    {
        Directory* one = new Directory("Folder1");
        Directory* two = new Directory("Folder2");
        Directory* three = new Directory("Folder3");

        File* fone =new File("File 1");
        File* ftwo =new File("File 2");
        File* fthree =new File("File 3");
        File* ffour =new File("File 4");
        File* ffive =new File("File 5");
        File* fsix =new File("File 6");
        File* fseven =new File("File 7");

        one->add(fone);
        one->add(ftwo);
        two->add(fthree);
        two->add(ffour);
        three->add(ffive);
        three->add(fsix);
        three->add(fseven);
        one->add(two);
        two->add(three);
        one->listFiles();
    }