1. ArrayAdapter を継承した FavoriteAdapter
- FavoriteAdapter は任意の型のデータを取りうる
- その型のデータに対する date(T), balance(T) の実装が必要
abstract class FavoriteAdapter<T>(context: Context, objects: List<T>)
: ArrayAdapter<T>(context, 0, objects) {
abstract fun date(data: T): String
abstract fun balance(data: T): Int
private val inflater = LayoutInflater.from(context)
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view: View = convertView ?: ItemViewHolder
.create(inflater, parent)
.also { it.view.tag = it }
.view
getItem(position)?.let {
(view.tag as ItemViewHolder).bind(date(it), balance(it))
}
return view
}
}
2. CursorAdapter を継承した HistoryAdapter
- CursorAdapter は任意の型のデータを取りうる
- その型のデータに対する date(T), balance(T) の実装が必要
- BaseData からその型のデータに変換するメソッドの実装が必要
abstract class HistoryAdapter<T>(context: Context)
: CursorAdapter(context, null, 0) {
abstract fun date(data: T): String
abstract fun balance(data: T): Int
abstract fun create(data: BaseData): T
private val inflater: LayoutInflater = LayoutInflater.from(context)
override fun newView(context: Context, c: Cursor, parent: ViewGroup) {
return ItemViewHolder.create(inflater, parent).also { it.view.tag = it }.view
}
override fun bindView(view: View, context: Context, c: Cursor) {
val baseData = convert(c)
val data = create(baseData)
(view.tag as ItemViewHolder).bind(date(data), balance(data))
}
private fun convert(c: Cursor): BaseData {
...
}
}
Delegation なし
データとして MyData をとる Adapter を用意してみましょう。
class MyDataAdapter(context: Context, objects: List<MyData>)
: FavoriteAdapter<MyData>(context, objects) {
override fun date(data: MyData) =
DateFormat.format(context.getString(R.string.format_date), data.getDate()).toString()
override fun balance(data: MyData) = data.getBalance()
}
class MyDataAdapter(context: Context) : HistoryAdapter<MyData>(context) {
override fun date(data: MyData) =
DateFormat.format(context.getString(R.string.format_date), data.getDate()).toString()
override fun balance(data: MyData) = data.getBalance()
override fun create(data: BaseData): MyData = MyData(data)
}
val adapter: FavoriteAdapter<*> = MyDataAdapter(context, list)
val adapter: HistoryAdapter<*> = MyDataAdapter(context)
FavoriteAdapter を継承した MyDataAdapter と HistoryAdapter を継承した MyDataAdapter をそれぞれ用意しました。しかし2つの Adapter の処理はほぼ同じなので、1つのクラスにまとめるのがよいでしょう。
そこで、まずは通常の Delegation パターンで実装してみます。
Delegation パターン
Adapter<T> インターフェースを用意し、FavoriteAdapter と HistoryAdapter に abstract で定義していたメソッドを Adapter のメソッドに置き換えます。
interface Adapter<T> {
fun date(data: T): String
fun balance(data: T): Int
fun create(data: BaseData): T
}
class FavoriteAdapter<T>(context: Context, objects: List<T>, private val adapter: Adapter<T>)
: ArrayAdapter<T>(context, 0, objects) {
fun date(data: T): String = adapter.date(data)
fun balance(data: T): Int = adapter.balance(data)
...
}
class HistoryAdapter<T>(val context: Context, private val adapter: Adapter<T>)
: CursorAdapter(context, null, 0) {
fun date(data: T): String = adapter.date(data)
fun balance(data: T): Int = adapter.balance(data)
fun create(data: BaseData): T = adapter.create(data)
...
}
Adapter を継承した MyDataAdapter を用意します。
class MyDataAdapter(private val context: Context) : Adapter<MyData> {
override fun date(data: MyData) =
DateFormat.format(context.getString(R.string.format_date3), data.getDate()).toString()
override fun balance(data: MyData) = data.getBalance()
override fun create(data: BaseData): MyData = MyData(data)
}
val adapter: FavoriteAdapter<*> = FavoriteAdapter(context, list, MyDataAdapter(context))
val adapter: HistoryAdapter<*> = HistoryAdapter(context, MyDataAdapter(context))
FavoriteAdapter と HistoryAdapter を継承しなくてよくなりました。
一方、FavoriteAdapter と HistoryAdapter の date() や balance() メソッドでは、Adapter のメソッドをそのまま呼び出しているだけです。
Class Delegation を使うと、このような明示的な記述をしなくてよくなります。
Class Delegation
FavoriteAdapter と HistoryAdapter も Adapter<T> を実装し、by を使ってコンストラクタでもらった adapter に処理を委譲します。
class FavoriteAdapter<T>(context: Context, objects: List<T>, private val adapter: Adapter<T>)
: ArrayAdapter<T>(context, 0, objects), Adapter<T> by adapter {
...
}
class HistoryAdapter<T>(val context: Context, private val adapter: Adapter<T>)
: CursorAdapter(context, null, 0), Adapter<T> by adapter {
...
}
Class Delegation により、FavoriteAdapter と HistoryAdapter では date() や balance() の明示的な記述をしなくてよくなりました。
0 件のコメント:
コメントを投稿