実践的なパターン
委譲でデコレーターを実装します
「実践的なパターン」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。
デコレーターパターン
デコレーターは、同じインターフェースを保ったまま動作を追加するために、オブジェクトをラップします。Kotlinの by キーワードを使えば、デコレーターは簡単に作れます。すべてを転送し、拡張したい部分だけをオーバーライドします。
基底コンポーネント
まず、シンプルなデータソースから始めます。デコレーターはこれをラップします。
interface DataSource {
fun fetch(): String
}
class NetworkSource : DataSource {
override fun fetch() = "raw-data"
}
fun main() {
println(NetworkSource().fetch())
}ログ出力デコレーター
このデコレーターはラップしたソースに処理を委譲し、対象となる呼び出しの前後にログ出力を追加します。
interface DataSource { fun fetch(): String }
class NetworkSource : DataSource { override fun fetch() = "raw-data" }
class LoggingSource(private val inner: DataSource) : DataSource by inner {
override fun fetch(): String {
println("fetching...")
val result = inner.fetch()
println("done")
return result
}
}
fun main() {
println(LoggingSource(NetworkSource()).fetch())
}キャッシュデコレーター
別のデコレーターは最初の結果をキャッシュするため、繰り返し呼び出しても内部のソースは呼び出されません。
interface DataSource { fun fetch(): String }
class NetworkSource : DataSource { override fun fetch() = "raw-data" }
class CachingSource(private val inner: DataSource) : DataSource by inner {
private var cached: String? = null
override fun fetch(): String {
return cached ?: inner.fetch().also { cached = it }
}
}
fun main() {
val s = CachingSource(NetworkSource())
println(s.fetch())
println(s.fetch()) // served from cache
}デコレーターの積み重ね
各デコレーター自体が DataSource なので、複数を積み重ねることができます。順序が重要です。外側のデコレーターが内側のデコレーターをラップします。
interface DataSource { fun fetch(): String }
class NetworkSource : DataSource { override fun fetch() = "raw-data" }
class LoggingSource(private val inner: DataSource) : DataSource by inner {
override fun fetch(): String { println("log"); return inner.fetch() }
}
class CachingSource(private val inner: DataSource) : DataSource by inner {
private var c: String? = null
override fun fetch() = c ?: inner.fetch().also { c = it }
}
fun main() {
val s = LoggingSource(CachingSource(NetworkSource()))
println(s.fetch())
println(s.fetch())
}検証デコレーター
デコレーターは入力値を検査することもできます。ここでは、実際のワーカーに委譲する前に入力を検証しています。
interface Processor { fun process(input: String): String }
class UpperProcessor : Processor { override fun process(input: String) = input.uppercase() }
class ValidatingProcessor(private val inner: Processor) : Processor by inner {
override fun process(input: String): String {
require(input.isNotBlank()) { "empty input" }
return inner.process(input)
}
}
fun main() {
println(ValidatingProcessor(UpperProcessor()).process("hello"))
}読み取り専用コレクションラッパー
委譲を使うと、アダプターラッパーを簡単に作成できます。ここではリストをラップし、すべてのリスト操作を転送しながら、独自の summary メソッドを追加しています。
class SummarizedList(private val inner: List<Int>) : List<Int> by inner {
fun total() = inner.sum()
}
fun main() {
val list = SummarizedList(listOf(1, 2, 3))
println(list.size)
println(list.total())
}呼び出し回数のカウント
デコレーターを使うと、透過的にメトリクスを追跡できます。実際の実装に手を加えずに監視できるため便利です。
interface Service { fun call(): String }
class RealService : Service { override fun call() = "ok" }
class CountingService(private val inner: Service) : Service by inner {
var calls = 0
private set
override fun call(): String {
calls++
return inner.call()
}
}
fun main() {
val s = CountingService(RealService())
s.call(); s.call()
println(s.calls)
}ここで委譲が有利な理由
継承でデコレーターを作るには、基底クラスを open にして、各デコレーターを具象クラスに結び付ける必要があります。委譲はインターフェースだけに依存するため、デコレーターは疎結合で、組み合わせやすいまま保てます。
パターンのチェックリスト
委譲デコレーターを作成するには、次の手順に従います。
- ラップするオブジェクトを
private valとして受け取る byでインターフェースに委譲する- 拡張するメンバーだけをオーバーライドする
- オーバーライドの中で内部オブジェクトを呼び出す
まとめて理解する
デコレーター、アダプター、プロキシは、いずれもクラス委譲から自然に導き出せます。小さなインターフェースと組み合わせることで、テストや拡張が容易な、柔軟で階層化されたシステムを構築できます。
理解度チェック
実践的な委譲パターンについての理解度を確認しましょう。
まとめ
委譲を使って実践的なデコレーターを作成しました。
- ログ出力、キャッシュ、検証、呼び出し回数のカウントを行うラッパー
- 各デコレーターが同じインターフェースなので、積み重ねて使用できる
- 拡張するメンバーだけをオーバーライドし、それ以外は転送する
これでクラス委譲のコースは完了です。
よくある質問
「実践的なパターン」レッスンは無料ですか?
はい。「実践的なパターン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。
「実践的なパターン」で何を学びますか?
委譲でデコレーターを実装します ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Kotlin Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「実践的なパターン」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このKotlin Academyレッスンでコードを書いて実行できますか?
はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。