デザインパターン

デザインパターン勉強会 第11回:Compositeパターン

はじめに

これは某社内で実施するデザインパターン勉強会で使用する資料です。
書籍「Java言語で学ぶデザインパターン」をベースに学習を進めますが、サンプルプログラムはC#に置き換えて解説します。

第1回:Iteratorパターン
第2回:Adapterパターン
第3回:Template Methodパターン
第4回:Factory Methodパターン
第5回:Singletonパターン
第6回:Prototypeパターン
第7回:Builderパターン
第8回:Abstract Factoryパターン
第9回:Bridgeパターン
第10回:Strategyパターン


Compositeパターンとは

Compositeパターンは、容器と中身を同一視して、再帰的な構造を作るパターンです。
木構造をイメージするとわかりやすいかと思います。

サンプルプログラムでは、PC上でファイル管理するためにフォルダの階層を作成するのをイメージしてください。


サンプルプログラム

クラス図

image.png


クラスの役割

クラス名 役割
IEntry FolderとFileを同一視するインターフェース
Folder フォルダを表すクラス
File ファイルを表すクラス
Program 動作確認用のクラス

IEntry

IEntryは、FolderクラスとFileクラスの構成を指定するためのインターフェースです。
・出力の処理を指定するOutput
で構成されています

    interface IEntry
    {
        void Output(int depth);
    }

Folder

Folderクラスはフォルダを表現しているクラスです
インターフェースの実装の他に、
フォルダ名を格納するnameフィールド
自身より下層のフォルダやファイルを持つentriesフィールドを持っています。

Outputメソッドでは、自身のNameを出力した後に自身より下層の要素のOutputメソッドを実行しています

    class Folder : IEntry
    {
        private string name;
        private List<IEntry> entries = new List<IEntry>();

        public Folder(string name)
        {
            this.name = name;
        }

        public void Output(int depth)
        {
            for(int i=0; i < depth; i++)
            {
                Console.Write("  ");
            }
            Console.WriteLine("Folder:"+name);
            foreach(IEntry entry in entries){
                entry.Output(depth+1);
            }

        }

        public void AddEntry(IEntry entry)
        {
            entries.Add(entry);
        }
    }

File

Fileクラスはファイルを表現しているクラスです
インターフェースで指定されたメソッドの他に
自身のファイル名を格納するNameフィールドを持っています。

    class File : IEntry
    {
        private string name;

        public File(string name)
        {
            this.name = name;
        }

        public void Output(int depth)
        {
            for (int i = 0; i < depth; i++)
            {
                Console.Write("  ");
            }
            Console.WriteLine("File:" + name);
        }

    }

Program

ファイルとフォルダのインスタンスを作成し、フォルダに追加します
追加する要素がファイルかフォルダかを意識せずに追加できます

    class Program
    {
        static void Main(string[] args)
        {
            var root = new Folder("root");
            var user = new Folder("user");
            var temp = new Folder("temp");
            var documents = new Folder("document");
            var game = new Folder("げぇむ");

            var gomi = new File("ごみ");
            var ika = new File("ika");
            var tako = new File("tako");
            var salmon = new File("salmon");

            //フォルダを追加
            root.AddEntry(user);
            root.AddEntry(temp);
            user.AddEntry(documents);
            user.AddEntry(game);

            //ファイルを追加
            temp.AddEntry(gomi);
            game.AddEntry(ika);
            game.AddEntry(tako);
            game.AddEntry(salmon);

            root.Output(0);

        }
    }

Program実行結果

Folder:root
  Folder:user
    Folder:document
    Folder:げぇむ
      File:ika
      File:tako
      File:salmon
  Folder:temp
    File:ごみ

まとめ

  • Compositeパターンは、容器と中身を同一視して、再帰的な構造を作るパターンです
  • 利用者は容器と中身を意識せずに使用することができます
  • ただし、利用できないメソッドがある場合は気をつける必要があります

サンプルコード

サンプルコードは以下で公開しています
https://github.com/Nanakusajp/CompositePattern