nprogram’s blog

気ままに、プログラミングのトピックについて書いていきます

Compositeパターン [C#]

Compositeパターン

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

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

クラス図

f:id:nprogram:20181112224053p:plain

クラス説明

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

実行イメージ

f:id:nprogram:20181107222825p:plain

コード例

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);
        }
    }
}