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

# はじめに
本エントリーは某社内で実施するデザインパターン勉強会向けの資料となります。
 本エントリーで書籍「[Java言語で学ぶデザインパターン入門](http://www.hyuki.com/dp/ "Java言語で学ぶデザインパターン入門")」をベースに学習を進めますが、サンプルコードはC#に置き換えて解説します。

第1回：[Iteratorパターン](http://qiita.com/Nuits/items/800f080d44b52e1cae18 "Iteratorパターン")
第2回：[Adapterパターン](http://qiita.com/Nanakusajp/items/747d1913b1e8bea8d340 "Adapterパターン")
第3回：[Template Methodパターン](https://qiita.com/_kyam/items/9b5722e6a9635af6e18b "Template Methodパターン")
第4回：[Factory Methodパターン](https://qiita.com/ayayo/items/3eece04bbc4b7504179a "Factory Methodパターン")
第5回：[Singletonパターン](https://qiita.com/Keenag/items/cae53d55cb953562fee4 "Singletonパターン")
第6回：[Prototypeパターン](https://qiita.com/aconit96/items/9235d30a07f508886c7e "Prototypeパターン")
第7回：[Builderパターン](https://qiita.com/Uesk/items/8f12be304671e9905795 "Builderパターン")
第8回：[Abstract Factoryパターン](https://qiita.com/buru/items/bb3930dda1bdd2b5f70b "Abstract Factoryパターン")
第9回：[Bridgeパターン](https://qiita.com/mitakaosamu/items/cff9a39953ae03092f43 "Bridgeパターン")
第10回：[Strategyパターン](https://qiita.com/a1146234/items/fdecc374b7225d99ab07 "Strategyパターン")
第11回：[Compositeパターン](https://qiita.com/Nanakusajp/items/32ed648eaadaa9910159 "Compositeパターン")

---

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

---

# サンプルクラス図
![decoratorクラス図.PNG](https://qiita-image-store.s3.amazonaws.com/0/194515/50e80941-e3ef-ff99-c135-00c6b252b063.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](https://qiita-image-store.s3.amazonaws.com/0/194515/631203d4-7d7c-257f-be16-1649b7c68ca2.png)


---
# まとめ

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


---


# サンプルコード
以下に公開しています。

https://github.com/yukyam/DecoratorPattern