LoginSignup
5
2

More than 5 years have passed since last update.

デザインパターン勉強会 第12回:Decoratorパターン

Last updated at Posted at 2017-10-31
1 / 14

はじめに

本エントリーは某社内で実施するデザインパターン勉強会向けの資料となります。
本エントリーで書籍「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パターン
第11回:Compositeパターン


Decoratorパターンとは

1つのオブジェクトに対して、飾りつけとなる機能をかぶせていくこと。それにより目的に合ったオブジェクトを仕上げていくようなデザインパターンのことをDecoratorパターンという。


サンプルクラス図

decoratorクラス図.PNG


各クラスの役割

名前     役割
Display 文字列表示用の抽象クラス
StringDisplay 一行だけからなる文字列表示用のクラス
Border 「飾り枠」を表す抽象クラス
SlideBorder 左右にのみ飾り枠をつけるクラス
FullBorder 上下にのみ飾り枠をつけるクラス
Program 動作テスト用のクラス

Displayクラス

Displayクラスは複数行からなる文字列を表示するための抽象クラスである。

public abstract class Display
    {
        public abstract int GetColums();
        public abstract int GetRows();
        public abstract string GetRowText(int row);
        public void Show()
        {
            for (int i = 0; i < GetRows(); i++)
            {
                Console.WriteLine(GetRowText(i));
            }
        }
    }

StringDisplayクラス

StringDisplayクラスはDisplayクラスのサブクラスである。1行の文字列を表示するクラス。


public class StringDisplay : Display
    {
        private readonly string lineString;

        public StringDisplay(string lineString)
        {
            this.lineString= lineString;
        }

        public override int GetColums()
        {
            Encoding sjisEnc = Encoding.GetEncoding("shift_jis");
            return sjisEnc.GetByteCount(lineString);
        }

        public override int GetRows()
        {
            return 1;
        }

        public override string GetRowText(int row)
        {
            return (row == 0) ? lineString: null;
        }
    }


Borderクラス

Displayクラスのサブクラスとして定義されている。飾り枠を表すクラスである。

public abstract class Border : Display
    {
        protected Display display;
        protected Border(Display display)
        {
            this.display = display;
        }
    }


SideBorderクラス

Borderクラスのサブクラスである。このクラスでは、文字列の左右に決まった文字を付けるものになっている。

public class SideBorder : Border
    {
        private char borderChar;

        public SideBorder(Display display, char ch) : base(display)
        {
            borderChar = ch;
        }

        public override int GetColums()
        {
            return 1 + display.GetColums() + 1;
        }

        public override int GetRows()
        {
            return display.GetRows();
        }

        public override string GetRowText(int row)
        {
            return borderChar + display.GetRowText(row) + borderChar;
        }
    }


FullBorderクラス

Borderクラスのサブクラスである。文字列の上下左右に文字を付けるものになっている。


public class FullBorder : Border
    {
        public FullBorder(Display display) : base(display)
        {
        }

        public override int GetColums()
        {
            return 1 + display.GetColums() + 1;
        }

        public override int GetRows()
        {
            return 1 + display.GetRows() + 1;
        }

        public override string GetRowText(int row)
        {
            if (row == 0)
            {
                return "+" + MakeLine('-', display.GetColums()) + "+";
            }
            else if (row == display.GetRows() + 1)
            {
                return "+" + MakeLine('-', display.GetColums()) + "+";
            }
            return "|" + display.GetRowText(row - 1) + "|";
        }

        private string MakeLine(char ch, int count)
        {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < count; i++)
            {
                stringBuilder.Append(ch);
            }
            return stringBuilder.ToString();
        }
    }

Programクラス

これは動作確認用のクラスとなっている。

public class Program
    {
        public static void Main(string[] args)
        {
            Display display1 = new StringDisplay("Hello,world!");
            Display display2 = new SideBorder(display1,'#');
            Display display3 = new FullBorder(display2);

            display1.Show();
            display2.Show();
            display3.Show();

            Display display4 = 
            new SideBorder(
                    new FullBorder(
                        new SideBorder(
                            new FullBorder(
                                new StringDisplay("こんにちは。")
                                ),
                                '*')
                            ),
                            '/'
                        );

            display4.Show();

            Console.ReadLine();
         }
    }

実行結果

実行すると以下のような結果が得られる

decorator.PNG


まとめ

  • 利用者にとって必要な表現を追加することで、既存のものを変更せずに機能を追加することができる

サンプルコード

以下に公開しています。

5
2
2

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
5
2