Kotlin Academy · レッスン

メンバーへの委譲

動作を合成します

レッスン 2/413 ステップ

「メンバーへの委譲」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。

振る舞いを組み立てる

実際のオブジェクトでは、複数の機能を組み合わせる必要があることがよくあります。複数のクラスを継承する代わりに、各機能を専用のメンバーオブジェクトに委譲できます。

2つの役割を1つのクラスで担う

あるクラスに読み取りと書き込みの両方を担わせるとします。2つのインターフェースを定義し、それぞれを別の実装に委譲します。

interface Reader { fun read(): String }
interface Writer { fun write(s: String): String }

class FileReader : Reader { override fun read() = "contents" }
class FileWriter : Writer { override fun write(s: String) = "wrote " + s }

class FileIO(r: Reader, w: Writer) : Reader by r, Writer by w

fun main() {
    val io = FileIO(FileReader(), FileWriter())
    println(io.read())
    println(io.write("data"))
}

複数の委譲先

1つのクラスから複数のインターフェースを同時に委譲し、それぞれを異なるメンバーに任せることができます。クラスは継承せずに、それらの振る舞いを組み合わせられます。

interface Logger { fun log(m: String): String }
interface Validator { fun valid(m: String): Boolean }

class ConsoleLogger : Logger { override fun log(m: String) = "LOG: " + m }
class LengthValidator : Validator { override fun valid(m: String) = m.isNotEmpty() }

class Service(l: Logger, v: Validator) : Logger by l, Validator by v

fun main() {
    val s = Service(ConsoleLogger(), LengthValidator())
    println(s.valid("hi"))
    println(s.log("started"))
}

委譲先をメンバーとして保持する

オーバーライドした処理の中で委譲先を参照する必要がある場合は、コンストラクタープロパティとして保持します。同じインスタンスが転送処理と独自のコードの両方で使われます。

interface Cache { fun get(k: String): String }

class MapCache : Cache {
    override fun get(k: String) = "value-of-" + k
}

class TracingCache(private val inner: Cache) : Cache by inner {
    override fun get(k: String): String {
        println("lookup " + k)
        return inner.get(k)
    }
}

fun main() {
    println(TracingCache(MapCache()).get("id"))
}

委譲と独自の状態を組み合わせる

委譲するクラスには、転送されたメンバーに加えて、独自のプロパティやメソッドを追加できます。これにより、組み合わせたオブジェクトをさらに拡張できます。

interface Engine { fun start(): String }
class V8 : Engine { override fun start() = "vroom" }

class Car(e: Engine) : Engine by e {
    var doors = 4
    fun honk() = "beep"
}

fun main() {
    val c = Car(V8())
    println(c.start())
    println(c.honk())
    println(c.doors)
}

実装を差し替える

委譲先は単なるメンバーなので、異なる基盤実装を使って同じラッパーを構築し、実行時に振る舞いを選べます。

interface Notifier { fun send(msg: String): String }
class EmailNotifier : Notifier { override fun send(msg: String) = "email: " + msg }
class SmsNotifier : Notifier { override fun send(msg: String) = "sms: " + msg }

class Alerts(n: Notifier) : Notifier by n

fun main() {
    println(Alerts(EmailNotifier()).send("hi"))
    println(Alerts(SmsNotifier()).send("hi"))
}

プロパティへの委譲

byの後の式には、コンストラクター呼び出しを含め、1回評価される任意の式を指定できます。パラメーターである必要はありません。

interface Greeter { fun greet() = "hi" }
class DefaultGreeter : Greeter

class Page : Greeter by DefaultGreeter()

fun main() {
    println(Page().greet())
}

ダイヤモンド問題を避ける

クラスでは振る舞いの多重継承はできません。しかし、複数のインターフェースをそれぞれ別のメンバーに委譲すれば、典型的なダイヤモンド問題をきれいに回避できます。

interface A { fun a() = "A" }
interface B { fun b() = "B" }
class AImpl : A
class BImpl : B

class Combined : A by AImpl(), B by BImpl()

fun main() {
    val c = Combined()
    println(c.a() + c.b())
}

コンポジションを前提に設計する

うまく組み合わせるには、次のようにします。

  • 小さく、役割を絞ったインターフェースを定義する
  • 再利用可能な実装を用意する
  • 組み合わせるクラスで各役割を委譲する

これにより、クラスの柔軟性とテストのしやすさを保てます。

メンバー委譲のまとめ

メンバーオブジェクトへの委譲を使うと、クラスは複数の部品から振る舞いを組み立てられます。継承を使わずに、多数のインターフェースを組み合わせ、一部だけをオーバーライドし、実装を差し替え、独自の状態を追加できます。

次は、直接比較します

委譲がどれほど柔軟かを見てきました。次のレッスンでは、委譲と継承を直接比較し、それぞれをいつ選ぶべきかを学びます。

理解度チェック

メンバーへの委譲についての理解度を確認しましょう。

まとめ

メンバー委譲について、次のことを学びました。

  • 複数のインターフェースを別々のオブジェクトに委譲する
  • 一部だけをオーバーライドし、独自の状態を追加する
  • 構築時に実装を差し替える
  • 多重継承に伴う問題を避ける

次は、委譲と継承を比較します。

無料で開始

AI チューターと学ぶ Kotlin — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
51
レッスン
203

よくある質問

「メンバーへの委譲」レッスンは無料ですか?

はい。「メンバーへの委譲」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。

「メンバーへの委譲」で何を学びますか?

動作を合成します ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Kotlin Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「メンバーへの委譲」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このKotlin Academyレッスンでコードを書いて実行できますか?

はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. byキーワード
  2. メンバーへの委譲
  3. 委譲と継承
  4. 実践的なパターン
← Kotlin Academyに戻る