Compositeパターン [C#][C++]

## Compositeパターン
Compositeパターンは、容器と中身を同一視して、再帰的な構造を作るパターンです。
利用者は容器と中身を意識せずに使用することができます。

Compositeパターンを使用しない場合は、容器と中身を意識する必要がある。
コード例では、DirecotryクラスのListに追加したインスタンスがフォルダーなのか、ファイルなのか、判定する処理が発生します。

## クラス図
![image.png](https://qiita-image-store.s3.amazonaws.com/0/293729/0d634afe-802e-09cf-70df-6c5456ae49c0.png)

## クラス説明
|クラス名|クラス説明|
|:--|:--|
|IEntry|FolderとFileを同一視するインターフェース|
|Directory|フォルダークラス|
|File|ファイルクラス|
|Program|ユーザークラス|

## 実行イメージ [C#]
```
Composite.Directory : root
    Composite.Directory : dir1
    Composite.Directory : dir2
        Composite.Directory : dir3
            Composite.File : file4
        Composite.File : file3
    Composite.File : file1
    Composite.File : file2
```

## コード [C#]

``` cs
using System;
using System.Collections.Generic;

namespace Composite
{
    class Program
    {
        static void Main(string[] args)
        {
            Directory root = new Directory("root");
            Directory dir1 = new Directory("dir1");
            Directory dir2 = new Directory("dir2");
            Directory dir3 = new Directory("dir3");

            File file1 = new File("file1");
            File file2 = new File("file2");
            File file3 = new File("file3");
            File file4 = new File("file4");

            // フォルダーを追加する
            root.AddEntry(dir1);
            root.AddEntry(dir2);
            dir2.AddEntry(dir3);

            // ファイルを追加する
            root.AddEntry(file1);
            root.AddEntry(file2);
            dir2.AddEntry(file3);
            dir3.AddEntry(file4);

            root.Output(0);

            Console.ReadLine();
        }
    }

    public interface IEntry
    {
        void Output(int someDepth);
    }


    public class Directory : IEntry
    {
        private string Name = null;
        private List<IEntry> Entries = new List<IEntry>();

        public Directory(string someName)
        {
            this.Name = someName;
        }

        public void AddEntry(IEntry someEntry)
        {
            Entries.Add(someEntry);
        }

        public void Output(int someDepth)
        {
            for (int i = 0; i < someDepth; i++)
            {
                Console.Write("    ");
            }

            Console.WriteLine("{0} : {1}", this.GetType().ToString(), this.Name);

            foreach (var item in Entries)
            {
                // 階層を1つ深くする
                item.Output(someDepth + 1);
            }
        }
    }

    public class File : IEntry
    {
        private string Name = null;

        public File(string someName)
        {
            this.Name = someName;
        }

        public void Output(int someDepth)
        {
            for (int i = 0; i < someDepth; i++)
            {
                Console.Write("    ");
            }

            Console.WriteLine("{0} : {1}", this.GetType().ToString(), this.Name);
        }
    }
}
```

## 実行イメージ [C++]
```
[Pattern 1]
Direcotry : root
    Direcotry : dir1
    Direcotry : dir2
        Direcotry : dir3
            File : file4
        File : file3
    File : file1
    File : file2
続行するには何かキーを押してください . . .
```

## コード [C++]
``` cpp
#include <iostream>
#include <vector>

class IEntry
{
public:
	virtual void Output(const int someDepth) = 0;
};

class Direcotry : public IEntry
{
private: 
	std::string mName;
	std::vector<IEntry*> mList;

public:
	Direcotry(std::string someName) : mName(someName) {}

public:

	void AddEntry(IEntry* someEntry)
	{
		this->mList.emplace_back(someEntry);
	}

	void Output(const int someDepth)
	{
		for (int i = 0; i < someDepth; i++)
		{
			std::cout << "    ";
		}

		std::cout << "Direcotry : " << this->mName.c_str() << std::endl;

		for (IEntry* item : mList)
		{
			// 階層を1つ深くする
			item->Output(someDepth + 1);
		}
	}
};

class File : public IEntry
{
private:
	std::string mName;

public:
	File(std::string someName) : mName(someName) {}

public:

	void Output(const int someDepth)
	{
		for (int i = 0; i < someDepth; i++)
		{
			std::cout << "    ";
		}

		std::cout << "File : " << this->mName.c_str() << std::endl;
	}
};

int main()
{
	std::cout << "[Pattern 1]" << std::endl;
	Direcotry root("root");
	Direcotry dir1("dir1");
	Direcotry dir2("dir2");
	Direcotry dir3("dir3");

	File file1("file1");
	File file2("file2");
	File file3("file3");
	File file4("file4");

	// フォルダーを追加する
	root.AddEntry(&dir1);
	root.AddEntry(&dir2);
	dir2.AddEntry(&dir3);

	// ファイルを追加する
	root.AddEntry(&file1);
	root.AddEntry(&file2);
	dir2.AddEntry(&file3);
	dir3.AddEntry(&file4);

	root.Output(0);

	system("pause");
}
```