デザインパターン勉強会⑤Singleton

<h1>はじめに</h1>
ZOOM勉強会の議事録です。
<a href="https://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%89%88Java%E8%A8%80%E8%AA%9E%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E5%85%A5%E9%96%80-%E7%B5%90%E5%9F%8E-%E6%B5%A9/dp/4797327030">「増補改訂版Java言語で学ぶデザインパターン入門」</a>を読んで、プログラム作成・パターンの理解を行います。
第5回はSingletonです。

<h1>Singleton</h1>
インスタンスが1つしか無いことを保証するパターンです。
Singletonクラスの役割は以下です。
<ul><li><b>Singleton</b></li>唯一のインスタンスを提供するクラス</ul>

また、コードは以下です。

```vb:Singleton
    Public Class Singleton

        '唯一のインスタンス
        Private Shared singleton = New Singleton()

        '外部からはインスタンス化できない
        Private Sub New()
        End Sub

        '唯一のインスタンスを返す
        Public Shared Function GetInstance() As Singleton
            Return singleton
        End Function

    End Class
```

Singletonパターンでは、以下の手順で唯一のインスタンスを保証しています。
<ul><li>コンストラクタをPrivateにし、外部からはインスタンス生成できない</li><li>フィールドに唯一のインスタンスを用意し、クラスのロード時にのみインスタンス化する</li></ul>


<h3>メリット</h3>
<ul><li>インスタンスが1つであることが保証される</li><li>1クラス内で完結しているパターンのため導入が簡単</li></ul>

<h3>デメリット</h3>
<ul><li>多くの場所からSingletonクラスを使用している場合、Singletonクラスの変更が多くの場所に影響を及ぼす</li><li>Singletonの派生クラスはSingletonでなくなるため、Singletonにしたい場合は再度実装する必要がある</li><li>使う側はこのクラスがSingletonであり、独自に定義されたメソッドでインスタンスを取得すると知っていなければならない</ul>


<h1>議論</h1>
調べたところSingletonは、デザインパターンの中でも不評なようです。
その理由として、Singletonは実質グローバル変数であるというような理由が見受けられました。

<h2>Singletonを活用する方法の議論</h2>
あまりSingletonは使わない方がいいのではという話しになる一方で、状態を持たない定数のような形であればいいのではという意見が出ました。
例えばマルバツゲームのマスの状態を表す「◯・✕・空」などの状態そのものをクラスで表現する場合です。
以下のような形です。

```vb:Maru
Public Class Maru : Implements ISquare
    Private Shared ReadOnly maru = New Maru()

    Private Sub New()
    End Sub

    Public Shared Function GetInstance() As ISquare
        Return maru
    End Function

    Public Function GetSquareImage() As Image Implements ISquare.GetSquareImage
        Return My.Resources.Maru
    End Function
End Class
```

このようにすることで、盤上にある同一の状態を1つのインスタンスのみで表現できます。
するとメモリの使用量が節約できるという意見でした。

<h2>Singletonに代わる方法</h2>
Singletonがだめなら他の方法が無いか調べ、<a href="https://www.amazon.co.jp/%E3%82%A2%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AB%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E3%81%AE%E5%A5%A5%E7%BE%A9-%E7%AC%AC2%E7%89%88-%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E9%96%8B%E7%99%BA%E3%81%AE%E7%A5%9E%E9%AB%84%E3%81%A8%E5%8C%A0%E3%81%AE%E6%8A%80-%E3%83%AD%E3%83%90%E3%83%BC%E3%83%88%E3%83%BBC%E3%83%BB%E3%83%9E%E3%83%BC%E3%83%81%E3%83%B3/dp/4797347783">アジャイルソフトウェア開発の奥義 第2版</a>でMonostateパターンというものを見つけました。

<h3>Monostate</h3>
インスタンス自体を一つにするのでなく、インスタンスの振る舞いを1つにします。
振る舞いを1つにすることで別々のインスタンスがあたかも1つのインスタンスかのように振る舞います。

```vb:Monostate
Public Class Monostate

    Private Shared itsX As Integer = 0

    Public Sub New()
    End Sub

    Public Sub SetX(ByVal x As Integer)
        itsX = x
    End Sub

    Public Function GetX() As Integer
        Return itsX
    End Function

End Class
```

以上のようにすべてのフィールド変数をShared（javaだとstatic）にし、すべてのインスタンスが、共有するフィールド変数にアクセスすることによって同じ振る舞いを実現しています。

<h3>メリット</h3>
<ul><li>通常のクラスのようにインスタンス化して使える</li><li>派生クラスにフィールドを共有させることができる</li><li>静的メソッドを強制されないため、メソッドをオーバーライドして異なる振る舞いを提供できる</li></ul>

<h3>デメリット</h3>
<ul><li>Singletonよりインスタンスの生成・削除の機会が多い</li></ul>

<br>
以上のようにSingletonが構造で唯一のインスタンスを保証している一方で、Monostateは振る舞いで唯一性を保証しています。


<h1>まとめ</h1>
第5回はSingletonを勉強しました。
話が色々逸れてしまいましたが、複数の方法を比較するとその方法の何が強くて何が弱いかを理解しやすかったです。
それぞれの強みを知って、適材適所にプログラムを書けたらと思います。