デザインパターンをkotlinで書いてみた Adapter編


オブジェクト指向で大切になるInterfaceの考え方やオブジェクトの再利用性を学ぶために「Java言語で学ぶデザインパターン入門」について学び、Javaとついでにkotlinで書いてみることにしました。
今回はAdapterについて書いてみます。

Adapterとは

すでに提供されているものと必要なものの間のずれを埋めるようなデザインパターンで、Wrapperパターンとも呼ばれるとの事。
元あるクラスを包んで必要な仕様に合わせる役割のパターン。

Adapterパターンの2種類の実装

  1. クラスで継承を用いたパターン
  2. インスタンスで委譲を用いたパターン の2種類が紹介されているが、今回は1番のクラスで継承を用いたパターンを実装してみたいと思います。

クラスで継承を用いたパターン

Eraクラス

このクラスは元々提供されていたクラスとします。
kotlinでは継承する場合、classはjavaのfinal扱いの為、openにして継承する必要があるとの事でclass定義の前にopenを指定する
参考:
https://www.atmarkit.co.jp/ait/articles/1804/24/news008.html

Era.java
class Era{
    private int year;
    public Era(int year) {
        this.year = year;
    }

    public int yearToReiwa() {
        return year - 2018;
    }

    public int yearToHeisei() {
        return year - 1988;
    }
}
Era.kt
open class Era(private val year: Int){
    fun yearToReiwa(): Int = this.year - 2018
    fun yearToHeisei(): Int = this.year - 1988
}

Printインターフェース

こちらは仕様として必要になり、求められている要件を満たすインターフェースです。
kolinではJavaでいうvoidを指定する場合Unitを使用する

Print.java
interface Print{
    public abstract void printAsReiwa();
    public abstract void printAsHeisei();
}
Print.kt
interface Print{
    fun printAsReiwa(): Unit
    fun printAsHeisei(): Unit
}

PrintEraクラス

このクラスはAdapterとなり、Eraクラスをラップして必要な要件を満たすクラスになります。
ポイントはEraクラスの実装を変えずに要求される仕様を実装できる点です。
継承する場合「:Era」のように指定し、継承先のコンストラクタを呼び出す場合は「:Era(year)」で呼び出せる

PrintEra.java
class PrintEra extends Era implements Print{
    public PrintEra(int year) {
        super(year);
    }
    public void printAsHeisei() {
        System.out.println("平成" + yearToHeisei() + "年");
    }
    public void printAsReiwa() {
        if(yearToReiwa() == 1) System.out.println("令和元年");
        else System.out.println("令和" + yearToReiwa() + "年");  
    }
}
PrintEra.kt
class PrintEra(private val year: Int) :Era(year), Print{
    override fun printAsHeisei(): Unit = println("平成" + yearToHeisei() + "年")
    override fun printAsReiwa() {
        if (yearToReiwa() == 1) println("令和元年") else println("令和" + yearToReiwa() + "年")
    }
}

Mainクラス

上記クラスを実際に動作させるMainクラスです。

AdapterSample.java
public class AdapterSample {
    public static void main(String[] args) {
        Print p = new PrintEra(2019);
        p.printAsHeisei();
        p.printAsReiwa();
    }
}
AdapterSample.kt
fun main(args: Array<String>){
    val p: Print = PrintEra(2019)
    p.printAsHeisei()
    p.printAsReiwa()
}
実行結果
平成31年
令和元年

クラス図

所感

  • 元々用意されていたクラスを変えずに新しく求められる要件に合わせて実装できるので、元々のメソッドを壊さずに実装できる事を学んだ。
  • また、mainクラスからは元々のEraクラスのメソッドを実装したAdapterクラスの実装が全く見えないので、再利用性も上がるとの事。
  • kotlinだと継承に定義にスーパークラスのコンストラクタの呼び出しができるのでコードの行数が少なくてすむ

参考

下記を参考にさせて頂き、大変読みやすく、理解しやすかったです。

JavaプログラマのためのKotlin入門