1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Kotlinでデザインパターン Template Method編

Last updated at Posted at 2019-01-26

はじめに

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

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

調べてみる

Template Methodについて調べてみます。
WikpediaではTemplate Methodは次のように説明されています。

Template Method パターンの目的は、ある処理のおおまかなアルゴリズムをあらかじめ決めておいて、
そのアルゴリズムの具体的な設計をサブクラスに任せることである。
そのため、システムのフレームワークを構築するための手段としてよく活用される

毎回思うのですがWikipediaはあぁそうなんだ〜で終わる説明ですね。
Template Methodの理解を深めるためには実装したほうが早そうですので実装していきます。

実装してみる

次の順序でファイルにPersonを出力する処理をアルゴリズムとします。
このアルゴリズムをTemplate Methodパターンを用いて実装したいと思います。

処理1. ファイルをオープンする
処理2. ファイルにPersonを書き込む
処理3. ファイルをクローズする

Person

Personについてですが次のように定義しました。
特にデータにはこだわりありませんのでFirstNameとLastNameを持つ単純なデータクラスとしました。

data class Person(val firstName : String, val lastName : String)

AbstractWriter

PersonAbstractWriterという抽象クラスのwriteメソッドにアルゴリズムを定義します。
処理1はOpen、処理2はprocess、処理3はcloseというメソッドで処理をします。
この3つのメソッドはabstractとなっていますのでサブクラスで具体的な処理を定義します。

このようにTemplate Methodパターンではまず、
ある処理の大まかなアルゴリズムを定義した抽象クラスを作成します。

abstract class AbstractWriter() {
    abstract fun open()
    abstract fun process(data : Person)
    abstract fun close()

    fun write(data : List<Person>)
    {
        // 処理1. ファイルをオープンする
        open()

       // 処理2. ファイルにデータを書き込む
        data.forEach {
            process(it)
        }

        // 処理3. ファイルをクローズする
        close()
    }
}

ConcreteWriter

次に抽象クラスのAbstractWriterを継承したサブクラスを定義し、
abstractで宣言していたメソッドをOverrideし具体的にどのように出力するか処理を実装していきます。
今回はPersonをCSV形式またはテキスト形式で書き込めるように処理を実装していきたいと思います。

CsvWriter

CSV形式での出力では次のようにヘッダーを出力したいです。
なのでファイルをオープンするときにヘッダーを書き込んでおきます。
あとはCSV形式ですのでカンマ区切りで各プロパティを書き込むようにします。

lastName,firstName
姫路,太郎
榊,真喜子
喜々津,優輔
class CsvWriter(name : String) : AbstractWriter()
{
    private val name : String = name
    private val header : String = "lastName,firstName\n"
    private var file : FileWriter? = null

    override fun open() {
        file = FileWriter(name)
        file?.write(header)
    }

    override fun process(data: Person) {
        val csv = "${data.lastName},${data.firstName}\n"
        file?.write(csv)
    }

    override fun close() {
        file?.close()
    }
}

TextWriter

テキスト形式ですのでPersonをそのまま書き込むだけなのですが、
次のように名簿のようにしたいと思いましたのであわせて番号も書き込むことにしました。

1 姫路 太郎
2 榊 真喜子
3 喜々津 優輔
class TextWriter(name : String) : AbstractWriter()
{
    private val name : String = name
    private var count : Int = 0
    private var file : FileWriter? = null

    override fun open() {
        file = FileWriter(name)
    }

    override fun process(data: Person) {
        count++

        var text = "${this.count} ${data.lastName} ${data.firstName}\n"
        file?.write(text)
    }

    override fun close() {
        file?.close()
        count = 0
    }
}

Main

サブクラスの定義が終わりましたのでMainから呼び出します。

fun main(args : Array<String>) {

    val persons = listOf<Person>(Person("太郎", "姫路"), Person("真喜子", "榊"), Person("優輔", "喜々津"))
    val csvWriter = CsvWriter( "persons.csv")
    val textWriter = TextWriter("persons.txt")

    csvWriter.write(persons)
    textWriter.write(persons)
}

Mainを実行しますと次のようなファイルが次の内容で出力されます。

lastName,firstName
姫路,太郎
榊,真喜子
喜々津,優輔
1 姫路 太郎
2 榊 真喜子
3 喜々津 優輔

おわりに

結論としてTemplate Methodパターンでやりたいことは処理の共通化です。

  1. インタフェースの共通化
  2. 処理順序の共通化

特に2の処理順序の共通化がTemplate Methodパターンの利点だと思います。
今回の例ですとオープンはいつクローズはいつと順序が決められているため、
サブクラスごとにオープンやクローズのタイミングが違うとかは絶対に起きなくなります。

このようにプログラマによって指針が違うような事柄が含まれる場合は、
Template Methodパターンを使って処理を共通化しておくとサブクラスがより管理しやすくなると思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?