デザインパターン勉強会⑨Bridge

<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>を読んで、プログラム作成・パターンの理解を行います。
第9回はBridgeパターンです。

<h1>Bridge</h1>
Bridgeパターンは、実装と機能を2つのクラスに分離するパターンです。

ブリッジパターンの役割は以下です。
<ul><li><b>Implementor</b></li>実装のクラス階層の最上位クラス<li><b>ConcreteImplementor</b></li>具体的な実装を行うクラス<li><b>Abstraction</b></li>機能の階層の最上位クラス<li><b>RefinedAbstraction</b></li>実際に機能を追加したもの</ul>


<h2>実装と機能</h2>
まず実装と機能について説明します。

<h3>実装</h3>
抽象クラス・インタフェースで定義した抽象メソッドを実装することを指します。
以下のように階層としては、横に伸びていきます。
AbstractClass
　-ConcreteCrass
　-AnotherConcreteClass

<h3>機能</h3>
あるクラスに新しいメソッドを追加するため、継承を行うことを指します。
階層としては、深さ方向に伸びていきます。
Something
　-SomethingGood
　　-SomethingBetter

<h2>Implementor</h2>
実装のクラス階層の最上位のクラスとなります。

```vb:DisplayImpl
    Public MustInherit Class DisplayImpl

        Public MustOverride Sub RawOpen()

        Public MustOverride Sub RawPrint()

        Public MustOverride Sub RawClose()

    End Class
```

<h2>ConcreteImplementor</h2>
具体的な実装を行うクラスです。
今回は`DisplayImpl`インタフェースのメソッドを実装して、装飾した文字列を表示します。

```vb:StringDisplayImpl

    '以下のような形で文字列を表示
    '+------+
    '|string|
    '+------+
    Public Class StringDisplayImpl : Inherits DisplayImpl

        ''' 文字の長さ
        Private width As Integer

        ''' 表示する文字列
        Private str As String

        ''' コンストラクタ
        Public Sub New(ByVal str As String)
            Me.str = str
            Me.width = str.Length
        End Sub

        ''' 開く
        Public Overrides Sub RawOpen()
            PrintLine()
        End Sub

        ''' 書く
        Public Overrides Sub RawPrint()
            Console.WriteLine("|" & str & "|")
        End Sub

        ''' 閉じる
        Public Overrides Sub RawClose()
            PrintLine()
        End Sub

        ''' (1)開く(2)閉じる　の実装
        Private Sub PrintLine()
            Console.Write("+")
            For i As Integer = 0 To width - 1
                Console.Write("-")
            Next
            Console.WriteLine("+")
        End Sub

    End Class
```

実装の階層としてもう一つ、wで文字を囲むものを作成します。

```vb:WWDisplay

    '以下のような形で文字列を表示
    'WwwwwwwwwwwwwW
    'Www string wwW
    'WwwwwwwwwwwwwW
    Public Class WWDisplay : Inherits DisplayImpl

        Private width As Integer

        Private str As String

        Public Sub New(ByVal str As String)
            Me.str = str
            Me.width = str.Length
        End Sub

        Public Overrides Sub RawOpen()
            PrintLine()
        End Sub

        Public Overrides Sub RawPrint()
            Console.WriteLine("Www " & str & " wwW")
        End Sub

        Public Overrides Sub RawClose()
            PrintLine()
        End Sub

        Private Sub PrintLine()
            Console.Write("W")
            For i As Integer = 0 To width + 5
                Console.Write("w")
            Next
            Console.WriteLine("W")
        End Sub

    End Class
```


<h2>Abstraction</h2>
機能のクラス階層の最上位のクラスになります。

```vb:Display
    Public Class Display

        ''' 抽象クラス
        Private _impl As DisplayImpl

        ''' コンストラクタ：抽象クラスでもらう
        Public Sub New(ByVal impl As DisplayImpl)
            Me._impl = impl
        End Sub

        ''' 開く
        Public Sub Open()
            _impl.RawOpen()
        End Sub

        ''' 書く
        Public Sub Print()
            _impl.RawPrint()
        End Sub

        ''' 閉じる
        Public Sub Close()
            _impl.RawClose()
        End Sub

    End Class
```

<h2>RefinedAbstraction</h2>
`Display`クラスに機能を追加したものになります。
今回は指定された回数表示するという機能を追加しています。

```vb:RefinedAbstraction
    Public Class CountDisplay : Inherits Display

        ''' コンストラクタ：抽象クラスでもらう
        Public Sub New(ByVal impl As DisplayImpl)
            '基底クラスのコンストラクタ
            MyBase.New(impl)
        End Sub

        ''' 指定された回数だけ、"書く"を繰り返す
        Public Sub MultiDisplay(ByVal times As Short)
            '開く
            Me.Open()

            '指定された回数だけ"書く"を繰り返す
            For i As Integer = 0 To times
                Print()
            Next

            '閉じる
            Me.Close()

        End Sub

    End Class
```

<h1>アンチパターン</h1>
実装と機能を2つのクラスに分離しなかった場合、指定された回数文字列を表示する機能をConcreteImplementor役の派生で実現することになります。
すると、`StringDisplayImpl`クラスと`WWDisplayImpl`クラス、両方にその機能が欲しい場合には、それぞれのクラスを派生して、それぞれで機能を追加しなければなりません。
この場合、ConcreteImplementor役の数だけクラスを増やす必要があります。
一方で、Bridgeパターンを使用した場合は、RefinedAbstraction役を1つ追加してやればよいだけとなります。

```vb:anti
    Public Class StringDisplayCount : Inherits StringDisplayImpl

        Public Sub New(ByVal str As String)
            MyBase.New(str)
        End Sub

        ''' 指定された回数だけ、"書く"を繰り返す
        Public Sub MultiDisplay(ByVal times As Short)
            '開く
            Me.RawOpen()

            '指定された回数だけ"書く"を繰り返す
            For i As Integer = 0 To times
                RawPrint()
            Next

            '閉じる
            Me.RawClose()

        End Sub

    End Class
```

<h1>まとめ</h1>
今回はBridgeパターンを学びました。
これも「継承より委譲」の一種なのかなと思いました。
機能と実装を意識することが殆どなかったので、今後はちゃんと意識して設計・コーディングを行っていきたいです。