任意の型Aの拡張関数の中でエンクロージング型Bのメンバを使いたいとき、
次のようなコードは自然ですが、fooはBの中でしか使えなくて不便です。
When we want to use a enclosing type B's members in any type A's extension function, the following code looks natural, but it's inconvenient that foo can be called in only B.
class B {
fun A.foo() {...}
}
下記のように同じ定義を繰り返さなくてはなりません。
なぜならFragmentActivityをいじることはできないからです。
Same definitions repeat as the below code because we cannot modify the sourcecode of FragmentActivity.
class RedActivity: FragmentActivity() {
fun DialogFragment.show(tag: String?) {
show(supportFragmentManager, tag)
}
}
class BlueActivity: FragmentActivity() {
fun DialogFragment.show(tag: String?) {
show(supportFragmentManager, tag)
}
}
そんなとき2つの提案があります。 1つめはインタフェースを使います。
Now I have two suggestions. The first is way to use a interface.
interface DialogFeature {
fun getSupportFragmentManager(): FragmentManager
fun DialogFragment.show(tag: String?) {
show(getSupportFragmentManager(), tag)
}
}
class RedActivity: FragmentActivity(), DialogFeature {
fun showMessage() {
myDialog.show("tag")
}
}
2つめは、拡張関数を返す拡張プロパティを定義することです。
The second is way to define an extension property which return an extension function.
val FragmentActivity.show: DialogFragment.(String?) -> Unit
get() = { tag ->
show(supportFragmentManager, tag)
}
class RedActivity: FragmentActivity() {
fun showMessage() {
myDialog.show("tag")
}
}
myDialog.show("tag")はこう解釈できます。
「this.showプロパティが参照されたので、DialogFragmentの拡張関数を返し、myDialogをレシーバ、"tag"を引数として呼び出す」
myDialog.show("tag") can be interpreted:
"this.show property was refered so it'll return DialogFragment's extension function and then call it with myDialog as a receiver and "tag" as an argument."
この方法だとIntelliJ IDEAのKotlinプラグインによる補完が効きません。
myDialog.のあとにサジェストされるメンバに、FragmentActivityの拡張プロパティであるshowは表示されません。
Code completion of IntelliJ IDEA Kotlin plugin dose not work in this way.
FragmentActivity's extension property show is not suggested as myDialog's members.
私は後者が好きです。 それっぽく "double context extension" パターンと名付けます。
I prefer the later. Plausibly I named this pattern "double context extension".
(Thank you for reading this to the end. Please point out my English errors to me.)