Kotlin
デザインパターン

Kotlinでデザインパターン Adapter編

はじめに

本記事はJava言語で学ぶデザインパターン入門を参考にしながら
JavaではなくKotlinで実装してみようというものです。

Java言語で学ぶデザインパターン入門

調べてみる

Adapterについて調べてみます。
WikipediaではAdapterについて次のように解説されています。

Adapter パターン(アダプター・パターン)とは、GoF (Gang of Four; 4人のギャングたち) によって定義されたデザインパターンの1つである。
Adapter パターンを用いると、既存のクラスに対して修正を加えることなく、インタフェースを変更することができる。
Adapter パターンを実現するための手法として継承を利用した手法と委譲を利用した手法が存在する。

またAdapterはWrapperとも呼ばれるみたいです。
私の周りではWrapperと呼ぶ方が多いですね、
恐らくAdapterよりWrapperのほうがイメージしやすいからだと思います。

AdapterパターンはWrapperパターンと呼ばれることもあります。
引用:Java言語で学ぶデザインパターン入門 Adapterパターン P16

だらだらと調べたことをまとめると
- Adapterは既存のクラスを修正せずにインタフェースを変更する
- Adapterは継承または移譲を利用して実装できる
- AdapterはWrapperとも呼ばれる

実装してみる

今回はそのまま実装しても面白くないので例を変えたいと思います。

Counter

既存のクラスとしてCounterを用意しました。
Counterは単純に数をインクリメント・デクリメント・リセットします。

open class Counter {

    var count : Int = 0
    fun increment() { count++ }
    fun decrement() { count-- }
    fun reset() { count = 0}
}

Entrance

Entranceは入退室を管理し入室人数を数えるためのインタフェースです。
今回はCounterにAdapterパターンを適応して、このインタフェースを実現します。

interface Entrance {
    val headcount : Int
    fun enter()
    fun exit()
    fun exitAll()
}

EntranceCounter

EntranceCounterがAdapterの役目を果たしEntranceのインタフェースを実現します。
はじめに述べたようにAdapterでは継承か移譲で実現するパターンがあります。
なので継承と移譲の2つのパターンを次のように実装します。

継承

class EntranceCounterInheritance : Counter() {
    val headcount : Int  get () = super.count
    fun enter() { super.increment() }
    fun exit() { super.decrement() }
    fun exitAll() { super.reset()}
}

移譲

class EntranceCounterDevolution : Entrance {
    private val counter : Counter = Counter()
    override val headcount : Int  get () = counter.count
    override fun enter() { counter.increment() }
    override fun exit() { counter.decrement() }
    override fun exitAll() { counter.reset()}
}

EntraceとCounterの「is-a」関係にはなっていないので、
今回は継承よりも移譲で実装するのが相応しそうです。
(このパターンの継承はただコードを共通に使えるからしちゃったってやつですね…)

Main

作成したEntranceの動作確認をします。
出力結果からわかるようにCounterのインタフェースを変更でき上手く動作しています。

fun main(args : Array<String>) {

    val east : Entrance = EntranceCounterInheritance()
    val west : Entrance = EntranceCounterDevolution()

    east.enter()
    println("東 ${west.headcount}人 入室中")
    east.exit()
    println("東 ${west.headcount}人 入室中")
    east.enter()
    println("東 ${west.headcount}人 入室中")
    east.enter()
    println("東 ${west.headcount}人 入室中")
    east.exitAll()
    println("東 ${west.headcount}人 入室中")

    west.enter()
    println("西 ${west.headcount}人 入室中")
    west.exit()
    println("西 ${west.headcount}人 入室中")
    west.enter()
    println("西 ${west.headcount}人 入室中")
    west.enter()
    println("西 ${west.headcount}人 入室中")
    west.exitAll()
    println("西 ${west.headcount}人 入室中")
}

Output
--------
 1 入室中
 0 入室中
 1 入室中
 2 入室中
 0 入室中
西 1 入室中
西 0 入室中
西 1 入室中
西 2 入室中
西 0 入室中