101010

とあるアプリ開発者のブログです。KotlinやSwiftが好き。たまにポえむってます。

委譲を使ったAdapter パターン

前回の続きで、もう少しAdapterパターンで遊んでみたいと思う。 継承を使ったAdapterパターンで作った「ドラえもんプログラム」をもとに、今度は委譲によるAdapterパターンに改造してみよう。

委譲を使ったAdapterパターン

前回も書いたとおりAdapterパターンには継承と委譲の2つがあった。今までは継承だけをやってきたが、ここで委譲も試してみよう。

書き換えるのはHumanクラスとRequesterクラスの2つだけだ。

まず、Humanクラスを抽象クラスに書き換えよう。この様になる。

abstract  class Human {
    abstract fun wannaFly()
    abstract fun wannaGoAnywhere()
}

そしてRequesterクラスはHumanクラスを継承した具象クラスになる。

class Requester: Human() {
    ...
}

Requesterクラスの実装の中身はこの様になる。Doraemnインスタンスを生成し、doraemonフィールドに仕事をさせているのがわかるだろう。

val doraemon = Doraemon()

override fun wannaFly() {
    println(doraemon.fetchTakeKopter())
}

override fun wannaGoAnywhere() {
    println(doraemon.fetchDokodemoDoor())
}

もちろんClientによるTargetへの扱い方は、委譲のときも継承の場合と全く変わらない。

fun main() {
    val nobita:Human = Requester()
    nobita.wannaFly()
    nobita.wannaGoAnywhere()
}

Doraemonがバージョンアップされた場合

さて、Doraemonクラスがバージョンアップして、Doraemon2として提供されることになった。 新しいAPIはこんな感じである。列挙型を使って、道具を呼び出さなければならないようだ。

enum class ToolType {
    TAKEKOPTER {
        override fun message() = "タケコプター!!!🚁"
    },
    DOKODEMODOOR {
        override fun message() = "どこでもドア!!!🚪"
    }; // セミコロンを忘れずに!

    abstract fun message():String
}

open class Doraemon2 {

    fun fetchTools(tool:ToolType):String {
        return tool.message()
    }

}

慌てることはない。Adapterパターンを採用していたおかげで、最小限の修正で済みそうである。 Requesterクラスを、新バージョンのDoraemon2に対応するには、次のようになった。

class Requester: Human() {

    val doraemon = Doraemon2()

    override fun wannaFly() {
        println(doraemon.fetchTools(ToolType.TAKEKOPTER))
    }

    override fun wannaGoAnywhere() {
        println(doraemon.fetchTools(ToolType.DOKODEMODOOR))
    }
}

これでClient側のプログラム修正は行わなくて済んだ。

まとめ

Client側では、Adapteeのクラスが古かろうが、新しかろうが知ったことではない。要求に答えてくれさえすれば良いのだ。このようなことを実現するのがAdapterの役割である。

プロジェクトの規模が大きくなった場合に、Adapterパターンは大活躍するであろう。導入時には少しややこしい部分があるが、メンテナンスなどにおいて他への影響が少なくて済む。

少しずつ使い方やメリットがわかってきたので、自分のプロジェクトにも意識的に活用してみたいと思う。

今回のサンプルはGitHubへ公開しておく。

https://github.com/araemon/AndroidExercise/tree/master/TryAdapterPatern2

参考