LoginSignup
12
20

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-11-12

Compositeパターン

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

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

クラス図

image.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#]

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++]

#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");
}
12
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
20