デザインパターン勉強会　第20回：Flyweightパターン


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

第1回：[Iteratorパターン](http://qiita.com/Nuits/items/800f080d44b52e1cae18)
第2回：[Adapterパターン](http://qiita.com/Nanakusajp/items/747d1913b1e8bea8d340)
第3回：[Template Methodパターン](http://qiita.com/_kyam/items/9b5722e6a9635af6e18b)
第4回：[Factory Methodパターン](http://qiita.com/ayayo/items/3eece04bbc4b7504179a)
第5回：[Singletonパターン](http://qiita.com/Keenag/items/cae53d55cb953562fee4)
第6回：[Prototypeパターン](http://qiita.com/aconit96/items/9235d30a07f508886c7e)
第7回：[Builderパターン](https://qiita.com/Uesk/items/8f12be304671e9905795)
第8回：[Abstract Factoryパターン](https://qiita.com/buru/items/bb3930dda1bdd2b5f70b)
第9回：[Bridgeパターン](https://qiita.com/mitakaosamu/items/cff9a39953ae03092f43)
第10回：[Strategyパターン](https://qiita.com/a1146234/items/fdecc374b7225d99ab07)　
第11回：[Compositeパターン](https://qiita.com/Nanakusajp/items/32ed648eaadaa9910159)
第12回：[Decoratorパターン](https://qiita.com/_kyam/items/3072a70c1f31f690e00c)
第13回：[Visitorパターン](https://qiita.com/ayayo/items/cf63041d047ea5b676c3)
第14回：[Chain of Responsibilityパターン](https://qiita.com/Keenag/items/6ef9cd9671aca38833d8)
第15回：[Facadeパターン](https://qiita.com/aconit96/items/60c924dbc69a059e5746#_reference-9d763076e525fb232407)
第16回：[Mediatorパターン](https://qiita.com/Uesk/items/5c3f2b2efd1cb4bb17ab#_reference-6f6607cd67571b932942)
第17回：[Observerパターン](https://qiita.com/buru/items/cc5c4cd32953f62c78c5)
第18回：[Mementoパターン](https://qiita.com/mitakaosamu/items/31d881ae14b28919e910#_reference-d009419cef2d0741bdc1)
第19回：[Stateパターン](https://qiita.com/a1146234/items/bba88081b0f84d70da1f)

---

# Flyweightパターンとは
　まず、flyweightというのはボクシングで最も体重が軽い階級のことを表しています。すなわちFryweightパターンというのは、オブジェクトを軽くするためのデザインパターンです。ここでいう重さはメモリの使用量を表しており、たくさんのメモリを使うオブジェクトを「重い」、少ししかメモリを使わないオブジェクトを「軽い」と表しています。　　
　　新しいクラスのインスタンスを作ると、そのインスタンスを保持するために、メモリが確保されます。そのクラスのインスタンスを沢山作ると、メモリの使用量が大きくなってしまいます。
　　すなわちFryweightパターンは、等価なインスタンスを別々の箇所で使用する際、一つのインスタンスを再利用することによってプログラムを省リソース化することを目的としているデザインパターンになります。

---

# クラス図
![無題aaaaa.png](https://qiita-image-store.s3.amazonaws.com/0/235246/2a23c48c-c5ee-8a39-3aaa-9cf0df40102b.png)



---

# 各クラスの役割
|名前|役割|
|:--|:--|
|BigChar|「大きな文字」を表すクラス|
|BigCharFactory|BigCharのインスタンスを共有しながら生成するクラス|
|BigString|BigCharを集めて作った「大きな文字列」を表すクラス|
|Program|動作テスト用のクラス|






---
# BigCharクラス

大きな文字を表現する(重いインスタンスを作る)クラス。　　
ファイルから大きな文字のテキストを読み込んでメモリ上に蓄え、printメソッドでそれを表示する。

```csharp
 class BigChar
    {
        //文字の名前
        private char charname;

        //大きな文字を表現する文字列
        private String fontdata;


        public BigChar(char charname)
        {
            this.charname = charname;

            String pass = String.Format("..\\..\\..\\Fryweightpt\\Fryweightpt\\Fryweightpt\\inputTxt\\big{0}.txt", this.charname);

            try
            {
                System.IO.StreamReader reader = (
                new System.IO.StreamReader(pass, System.Text.Encoding.Default)
                  );

                String line;

                while ((line = reader.ReadLine()) != null)
                {
                    fontdata += line + "\n";

                }
            }
            catch (IOException e)
            {
                this.fontdata = charname + "?";
            }

        }

        //大きい文字を表示
        public void print()
        {
            Console.Write(fontdata);
        }

    }
```

---
# BigCharFactoryクラス

BigCharのインスタンスを生成するクラス。　　
同じ文字に対応するBigCharのインスタンスが既に作ってあった場合は、それを利用し、新しいインスタンスは作らない。また、factoryクラスは複数生成する必要がないため、Singletonパターンで実装されています。

```csharp
 class BigCharFactory
    {
        //既に作ったBigCharのインスタンスを管理
        private Hashtable pool = new Hashtable();

        //Singletonパターン
        private static BigCharFactory bigCharFactory = new BigCharFactory();

        private BigCharFactory()
        {
        }

        public static BigCharFactory getInstance()
        {
            return bigCharFactory;
        }

        //BigCharのインスタンス作成
        public BigChar getBigChar(char charname)
        {
            BigChar bigChar = (BigChar)pool["" + charname];

            if (bigChar == null)
            {
                bigChar = new BigChar(charname);
                pool.Add("" + charname, bigChar);
            }
            return bigChar;
        }

    }
```

---

# BigStringクラス

BigCharを集めた大きな文字列を表すクラス。　　
BigCharのインスタンスを保持する。

```csharp
class BigString
    {
        //「大きな文字」の配列
        private BigChar[] bigchars;

        public BigString(String str)
        {
            bigchars = new BigChar[str.Length];
            BigCharFactory bigCharFactory = BigCharFactory.getInstance();
            
            for(int i=0; i< bigchars.Length; i++)
            {
                bigchars[i] = bigCharFactory.getBigChar(str[i]);
            }
        }

        //表示
        public void print()
        {
            for(int i=0; i < bigchars.Length; i++)
            {
                bigchars[i].print();
            }
        }
    }
```


---

# Programクラス

動作テスト用のクラス。　　
引数で与えられた文字列を元に、BigStringのインスタンスを作り、それを表示する。

```csharp

class Program
    {
        static void Main(string[] args)
        {
            if(args.Length == 0)
            {
                Console.WriteLine("please enter a number !");
                Console.ReadLine();
                System.Environment.Exit(0);

                    }
            BigString bigString = new BigString(args[0]);

            bigString.print();
            Console.ReadLine();
        }
    }
```
# txtファイル
大きな文字を構成しているデータ。
文字の前にbigという文字列を付けたファイル名。

例 : big1.txt

```
--------------
-----##-------
--#####-------
-----##-------
-----##-------
-----##-------
-----##-------
-----##-------
--########----
-------------- 
```

---
#プログラム実行結果
実行時引数を 0121　とした場合。

```
----#####-----
--##-----##---
--##-----##---
--##-----##---
--##-----##---
--##-----##---
----#####-----
--------------

--------------
-----##-------
--#####-------
-----##-------
-----##-------
-----##-------
-----##-------
-----##-------
--########----
--------------

--------------
----######----
--##----###---
--------###---
-----###------
---##---------
-##-----------
-##########---
--------------

--------------
-----##-------
--#####-------
-----##-------
-----##-------
-----##-------
-----##-------
-----##-------
--########----
--------------
```

---
#考察
・重複したインスタンスを生成することがなくなるため、インスタンスの管理をfactoryに任せておけば、既に生成している、いないの管理をインスタンスを使う側でする必要がなくなる。

・インスタンスを共有しているので、一つのインスタンスを変更するだけでそのインスタンスを使っている複数箇所に同時に変更が反映されてしまう。
　　→複数箇所に共有させるべき情報だけ、Fryweight役に持たせるべきである。