"double context extension" pattern (命名適当) #kotlin
任意の型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.)