Kotlin 戻り値をジェネリクスとした抽象メソッドの定義と実装、TemplateMethodの応用


APIで取得したJsonデータをパース、Modelメンバにパースした値をセットしてオブジェクトを返す。という処理をtemplate method的な固有実装のみサブクラスに実装したかったので勉強しました。

クラス関係

//ジェネリクスは継承先のクラスが指定する
open abstract class ApiModel<T> {
}

class DataModel:ApiModel<BlogModel>() {
    var last_name = ""  //jsonから取得した値が入ります
    var first_name = ""
}

抽象メソッドの定義と実装

各サブラクスにmodelオブジェクトを生成する処理を記述する

open abstract class ApiModel<T> {
    abstract fun createModel(jsonObject:JSONObject):T
}

class DataModel:ApiModel<DataModel>() {
    var last_name = ""  //jsonから取得した値が入ります
    var first_name = ""

    override fun createModel(jsonObject:JSONObject):DataModel{
        val model = DataModel()
        model.last_name = jsonObject.getString("last_name")
        model.first_name = jsonObject.getString("first_name")
        return model
    }
}

親クラスにtemplate methodの呼び出しメソッドを記述

Superクラスはサブクラスから渡されたジェネリクスに応じたオブジェクトを呼び出し元に返せばよい

open abstract class ApiModel<T> {
    abstract fun createModel(jsonObject:JSONObject):T
    //jsonが配列の場合
    fun stringToModels(apiResponseJson: String):List<T>{
        val returnModels = mutableListOf<T>()
        val jsons = JSONArray(apiResponseJson)
        (0..(jsons.length() - 1)).forEach { i ->
            //createModelはサブクラスで実装
            val model = createModel( jsons.getJSONObject(i) )
            returnModels.add(model)
        }
        return returnModels as List<T>
    }

    //jsonが単オブジェクトの場合
    fun stringToModel(apiResponseJson: String):T{
        val json = JSONObject(apiResponseJson)
        //createModelはサブクラスで実装
        val model = createModel( json )
        return model
    }
}

使用例

val dataModel:DataModel = DataModel().stringToModel("単オブジェクトのJson文字列")
val dataModels:List<DataModel> = DataModel().stringToModels("ルートが配列のJson文字列")

他のAPIを使用するクラスの場合、

class FooModel:ApiModel<FooModel>() {
    var foo_name = ""  

    override fun createModel(jsonObject:JSONObject):FooModel{
        val model = FooModel()
        model.foo_name = jsonObject.getString("foo_name")
        return model
    }
}

と、こんな感じでジェネリクスとJsonに関わる構造のみ記述すればよい。