Skip to content

Instantly share code, notes, and snippets.

@ohtsuchi
Last active November 27, 2017 10:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ohtsuchi/1dcb980c82b2748af3a5b59604168824 to your computer and use it in GitHub Desktop.
Save ohtsuchi/1dcb980c82b2748af3a5b59604168824 to your computer and use it in GitHub Desktop.
Kotlinスタートブック(赤べこ本) 第10章 の 写経

Kotlinスタートブック(赤べこ本) 第10章 の 写経

第10章 Interface


1. Interface の 定義と実装

list 10.1 interface, list 10.2 interface の実装例

// list 10.1
interface Greeter {
    val language: String
    fun sayHello(target: String)
}

// list 10.2 `:` の後に interface 名
class EnglishGreeter : Greeter {
    // `override`
    override val language = "English"
    // `override`
    override fun sayHello(target: String) {
        println("Hello, $target!")
    }
}

fun main(args: Array<String>) {
    val g: Greeter = EnglishGreeter()
    println(g.language)       // English
    g.sayHello("Kotlin")      // Hello, Kotlin!
}

list 10.3 複数の interface の実装

open class Superclass

interface Foo
interface Bar

class MyClassa : Superclass(), Foo, Bar

2. デフォルト実装 と コンフリクトの回避

list 10.4 同一シグニチャ の メソッドの実装

interface Foo {
    fun execute()
}

interface Bar {
    fun execute()
}

class FooBar : Foo, Bar {
    // `override`
    override fun execute() {
        println("FooBar")
    }
}

fun main(args: Array<String>) {
    var f: Foo = FooBar()
    var b: Bar = FooBar()
    f.execute()  // FooBar
    b.execute()  // FooBar
}

list 10.5 interface と class で 同一シグニチャ メソッド

interface Foo {
    fun execute()
}

open class Superclass {
    fun execute() {
        println("Superclass")
    }
}

class FooSubclass : Superclass(), Foo

fun main(args: Array<String>) {
    val f: Foo = FooSubclass()
    f.execute()  // Superclass
}

list 10.6 実装を持った 2つの interface の実装, list 10.7 interface Hoge の実装を使用

// list 10.6
interface Hoge {
    fun execute() {
        println("Hoge")
    }
}

interface Fuga {
    fun execute() {
        println("Fuga")
    }
}

//
// list 10.6 コンパイルエラー. 複数の実装 -> 曖昧さが発生
//
// Class 'HogeFuga' must override public open fun execute():Unit defined in Hoge
//   because it inherits multiple interface methods of it
//
class HogeFuga : Hoge, Fuga

// 追記(単独で implement するのは問題無い)
class Hoge2 : Hoge // OK
class Fuga2 : Fuga // OK

// 
// list 10.7 `Hoge` の実装を使用
// 
class HogeFuga2 : Hoge, Fuga { // OK
    // `override`
    override fun execute() {
        super<Hoge>.execute()  // `super<interface または class>.method()`
    }
}

fun main(args: Array<String>) {
    val h: Hoge = HogeFuga2()
    val f: Fuga = HogeFuga2()
    h.execute()     // Hoge
    f.execute()     // Hoge
}

3. Interface の 継承

list 10.8

interface Foo {
    fun aaa()
    fun bbb()
}

interface Bar : Foo {
    override fun aaa() {}
    fun ccc()
}

class Baz : Bar {
    override fun bbb() {}
    override fun ccc() {}
}

4. Delegation

list 10.9 interface Greeter, list 10.10 class JapaneseGreeterWithRecording

// list 10.9
interface Greeter {
    fun sayHello(target: String)
    fun sayHello()
}

// 赤べこ本には記述無いが, 多分こんな実装
open class JapaneseGreeter : Greeter {
    override fun sayHello(target: String) {
        println("こんにちは, ${target}さん!")
    }
    override fun sayHello() {
        sayHello("匿名")
    }
}

//
// list 10.10 継承
//
class JapaneseGreeterWithRecording : JapaneseGreeter() {
    private val _targets: MutableSet<String> = mutableSetOf()

    val targets: Set<String>
        get() = _targets

    // `override`
    override fun sayHello(target: String) {
        _targets += target
        super.sayHello(target)  // superclass の 実装を利用
    }
}

fun main(args: Array<String>) {
    val greeter = JapaneseGreeterWithRecording()
    greeter.sayHello("うらがみ") // こんにちは, うらがみさん!
    greeter.sayHello("がくぞ")   // こんにちは, がくぞさん!
    println(greeter.targets)     // [うらがみ, がくぞ]

    greeter.sayHello("***")     // こんにちは, ***さん!
    greeter.sayHello()          // こんにちは, 匿名さん!
    println(greeter.targets)    // [うらがみ, がくぞ, ***, 匿名]  // "匿名" も記録されている <- 期待しない動作
}
  • sayHello() 呼び出し時の "匿名" も記録されている <- 期待しない動作

list 10.11 delegation を行うバージョン

// list 10.9
interface Greeter {
    fun sayHello(target: String)
    fun sayHello()
}

open class JapaneseGreeter : Greeter {
    override fun sayHello(target: String) {
        println("こんにちは, ${target}さん!")
    }
    override fun sayHello() {
        sayHello("匿名")
    }
}

//
// list 10.11 `JapaneseGreeter` の 継承 をやめて `Greeter` を実装
//
class JapaneseGreeterWithRecording : Greeter {
    // <委譲先>
    private val g: Greeter = JapaneseGreeter()

    private val _targets: MutableSet<String> = mutableSetOf()

    val targets: Set<String>
        get() = _targets

    // <追加>
    override fun sayHello() {
        g.sayHello()                        // <委譲>
    }

    override fun sayHello(target: String) {
        _targets += target
        // <変更>
        // super.sayHello(target)
        g.sayHello(target)                  // <委譲>
    }
}

fun main(args: Array<String>) {
    val greeter = JapaneseGreeterWithRecording()
    greeter.sayHello("うらがみ") // こんにちは, うらがみさん!
    greeter.sayHello("がくぞ")   // こんにちは, がくぞさん!
    println(greeter.targets)     // [うらがみ, がくぞ]

    greeter.sayHello("***")     // こんにちは, ***さん!
    greeter.sayHello()          // こんにちは, 匿名さん!
    println(greeter.targets)    // [うらがみ, がくぞ, ***] // "匿名" が記録されなくなった <- 期待する動作
}

list 10.12 class delegation を使った例

  • 委譲先
    • constructor で渡す
    • by で指定
  • 必要な分だけ override すればok
// list 10.9
interface Greeter {
    fun sayHello(target: String)
    fun sayHello()
}

open class JapaneseGreeter : Greeter {
    override fun sayHello(target: String) {
        println("こんにちは, ${target}さん!")
    }
    override fun sayHello() {
        sayHello("匿名")
    }
}

//
// list 10.12 委譲先 を constructor で受け取る && `by` で 委譲先を指定
//
class JapaneseGreeterWithRecording(private val g: Greeter) : Greeter by g { // `by`
    private val _targets: MutableSet<String> = mutableSetOf()

    val targets: Set<String>
        get() = _targets

    override fun sayHello(target: String) {
        _targets += target
        g.sayHello(target)                  // <委譲>
    }
}

fun main(args: Array<String>) {
    val greeter = JapaneseGreeterWithRecording(JapaneseGreeter())
    greeter.sayHello("うらがみ") // こんにちは, うらがみさん!
    greeter.sayHello("がくぞ")   // こんにちは, がくぞさん!
    println(greeter.targets)     // [うらがみ, がくぞ]

    greeter.sayHello("***")     // こんにちは, ***さん!
    greeter.sayHello()          // こんにちは, 匿名さん!
    println(greeter.targets)    // [うらがみ, がくぞ, ***]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment