【Kotlin】レッスン5-11:インターフェースを理解しよう

記事内に商品プロモーションを含む場合があります

この記事で学べる知識:インターフェース

この記事の練習問題を解くために必要な知識:
基礎文法、制御構造、関数、コレクション(レッスン1~4)クラスの定義と使用プライマリコンストラクタセカンダリコンストラクタアクセス修飾子とカプセル化クラスメンバとインスタンスメンバクラスの継承メソッドのオーバーライドクラスの拡張抽象クラスインターフェースデータクラス

<<前のページ Kotlin記事一覧 次のページ>>

Kotlinの文法「インターフェース」とは

ここではインターフェースの意味や使い方を学習します。必要ない方はここをクリックして練習問題へ飛びましょう。



Kotlinではオブジェクト指向の重要な概念として「インターフェース」があります。

インターフェースはクラスが持つべき共通の機能や特性を定義する仕組みです。

本記事では、インターフェースの基本から具体的な使用例、さらに抽象クラスとの違いについて解説します。

【初心者向け】Kotlinのオブジェクト指向を分かりやすくまとめた概念図。 特にクラスの継承、オーバーライド、抽象クラス、インターフェース、データクラスの関係性を視覚的に理解できるようまとめている。

インターフェースとは?

インターフェースとは、複数のクラスに共通するプロパティやメソッドを定義するための設計図のようなものです。

これにより異なるクラスに一貫性のある機能を持たせることができます。

インターフェース自体はインスタンス化できず、具体的な処理はインターフェースを実装するクラスに任されます。

例えるなら、インターフェースは「契約書」で、実装するクラスがその契約内容を実行に移す役割を果たします。

インターフェースの定義と実装

Kotlinでのインターフェースはinterfaceキーワードを使用して定義します。

またインターフェースには抽象プロパティや抽象メソッドのほか、具体的なメソッドを記述することもできます。

// インターフェースの定義
interface Animal {   // Animalインターフェースの定義
    val name: String // 抽象プロパティ
    fun makeSound()  // 抽象メソッド
    fun sleep() {    // 具体的なメソッド
        println("$name is sleeping")
    }
}

// インターフェースの実装
class Dog(override val name: String) : Animal { // Animalインターフェースを実装したDogクラスの定義
    override fun makeSound() {                  // 抽象メソッドをオーバーライド
        println("$name says Woof!")
    }
}

class Cat(override val name: String) : Animal { // Animalインターフェースを実装したCatクラスの定義
    override fun makeSound() {                  // 抽象メソッドをオーバーライド
        println("$name says Meow!")
    }
}

このコードではAnimalというインターフェースをDogクラスとCatクラスがそれぞれ実装しています。

インターフェースの使用例

以下は上記のコードを使用した具体例です。

fun main() {
    val dog = Dog("Buddy") // Dogクラスのインスタンス生成
    val cat = Cat("Kitty") // Catクラスのインスタンス生成

    dog.makeSound()        // Buddy says Woof!
    cat.makeSound()        // Kitty says Meow!

    dog.sleep()            // Buddy is sleeping
    cat.sleep()            // Kitty is sleeping
}
  • DogCatのインスタンスを作成し、それぞれがAnimalインターフェースを実装していることを確認します。
  • 抽象メソッドmakeSoundは具体的な実装を持ち、クラスごとに異なる動作をします。
  • インターフェースに具体的なメソッドsleepを定義することで、全ての実装クラスで共通の処理を記述できます。

インターフェースと抽象クラスとの違い

インターフェースと抽象クラスには似た部分がありますが、それぞれ異なる用途があります。

以下に主な違いを挙げます。

  1. 多重継承の可否:
    • インターフェース: 複数のインターフェースを同時に実装可能。
    • 抽象クラス: 普通の親クラス同様、1つのクラスしか継承できない。
  2. メンバーの種類:
    • インターフェース: 抽象メソッドやプロパティのほか、具体的なメソッドも定義可能。
    • 抽象クラス: 抽象的なメンバーだけでなく、状態(プロパティ)を持つ具体的なメソッドも定義可能。
  3. 使用場面:
    • インターフェース: クラス間の「共通機能」を定義するのに最適。
    • 抽象クラス: 基本的な動作やデータを持つ「基底クラス」を提供する場合に使用。
// 抽象クラスの例
abstract class Vehicle(val name: String) {
    abstract fun move()
    fun stop() {
        println("$name stops.")
    }
}

// インターフェースの例
interface Movable {
    fun move()
}

 

インターフェースは「動作を定義」するのに対し、抽象クラスは「状態を伴う動作の共通化」に向いています。

インターフェースを使うメリット

  1. コードの再利用性が向上: 共通の機能をインターフェースに定義することで、異なるクラスで再利用できます。
  2. 多重継承が可能: Kotlinではクラスの継承は1つのみですが、インターフェースは複数実装が可能です。
  3. 設計の柔軟性: クラス間の結合度を下げ、変更や拡張に強い設計が可能です。

まとめ

インターフェースはKotlinでオブジェクト指向設計を行う上で欠かせない要素です。

共通のプロパティやメソッドを定義することで、コードの再利用性と一貫性を高めます。

また抽象クラスとの違いを理解することで、設計の目的に応じた適切な選択が可能になります。

本記事で学んだ基本構文や使用例を基に、ぜひインターフェースを活用してみてください。

インターフェースの練習問題:動物園管理システムを作ってみよう

インターフェースを利用して動物園の動物を管理するシステムを作成しましょう。

物の鳴き声や情報をインターフェースを用いて統一的に扱い、動物を動的に管理する仕組みを学びます。

この問題の要件

以下の要件を満たすコードを書いてください。

  1. Animal インターフェースを定義し、以下を実装すること:
    • 鳴き声を出力する makeSound メソッド。
    • 動物の名前と年齢を表示する displayInfo メソッド。
  2. Lion クラスを作成し、Animal インターフェースを実装すること:
    • 名前と年齢を保持するプロパティ nameage を定義。
    • makeSound メソッドで「[名前] が吠えました: ガオー!」を表示。
    • displayInfo メソッドで「ライオン – 名前: [名前], 年齢: [年齢] 歳」を表示。
  3. Elephant クラスを作成し、Animal インターフェースを実装すること:
    • 名前と年齢を保持するプロパティ nameage を定義。
    • makeSound メソッドで「[名前] が鳴きました: パオーン!」を表示。
    • displayInfo メソッドで「ゾウ – 名前: [名前], 年齢: [年齢] 歳」を表示。
  4. Zoo クラスを作成し、以下を実装すること:
    • Animal 型のオブジェクトを格納する animals リストを定義。
    • Animal をリストに追加する addAnimal メソッドを作成。
      動物をリストに追加した後「動物が追加されました。」と表示し、追加された動物の情報を displayInfo メソッドで表示。
    • リスト内の全ての動物の情報を表示する displayAllAnimals メソッドを作成。
  5. メイン関数を作成し、以下を実施すること:
    • Zoo クラスのインスタンスを作成。
    • Lion クラスと Elephant クラスのインスタンスを作成。
    • Zoo インスタンスに動物を追加。
    • Zoo 内の全ての動物情報を表示。
    • 各動物の鳴き声を表示。

ただし、以下のような実行結果となること。

----- ↓出力される結果の例↓ -----

動物が追加されました。
ライオン - 名前: レオ, 年齢: 5 歳
動物が追加されました。
ゾウ - 名前: エリー, 年齢: 10 歳
すべての動物の情報:
ライオン - 名前: レオ, 年齢: 5 歳
ゾウ - 名前: エリー, 年齢: 10 歳
レオ が吠えました: ガオー!
エリー が鳴きました: パオーン!

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。

1:Animalインターフェースの定義
  □ makeSound関数の定義
  □ displayInfo関数の定義
2:Lionクラスの定義
  □ プライマリコンストラクタでnameとageプロパティを定義
  □ Animalインターフェースを実装
  □ makeSound関数をオーバーライドし、名前と鳴き声を出力
  □ displayInfo関数をオーバーライドし、ライオンの情報を出力
3:Elephantクラスの定義
  □ プライマリコンストラクタでnameとageプロパティを定義
  □ Animalインターフェースを実装
  □ makeSound関数をオーバーライドし、名前と鳴き声を出力
  □ displayInfo関数をオーバーライドし、ゾウの情報を出力
4:Zooクラスの定義
  □ MutableList型のanimalsプロパティを初期化
  □ addAnimal関数の定義
  □ □ リストに動物を追加
  □ □ 「動物が追加されました。」と出力
  □ □ 追加された動物の情報を表示
  □ displayAllAnimals関数の定義
  □ □ 「すべての動物の情報:」と出力
  □ □ for文で全ての動物の情報を表示
5:main関数の定義
  □ Zooクラスのインスタンスを作成
  □ Lionクラスのインスタンスを作成
  □ Elephantクラスのインスタンスを作成
  □ addAnimal関数を用いてライオンとゾウを動物リストに追加
  □ displayAllAnimals関数を用いて全ての動物情報を表示
  □ makeSound関数を用いて各動物の鳴き声を出力

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

// インターフェース Animal を定義
interface Animal {
    // 動物の鳴き声を出すメソッド
    fun makeSound()
    // 動物の情報を表示するメソッド
    fun displayInfo()
}

// Animal インターフェースを実装する Lion クラスを定義
class Lion(val name: String, val age: Int) : Animal {
    // makeSound メソッドの実装
    /*【穴埋め問題1】
    ここに makeSound メソッドをオーバーライドし、ライオンの鳴き声を出すコードを書いてください。
    */

    // displayInfo メソッドの実装
    /*【穴埋め問題2】
    ここに displayInfo メソッドをオーバーライドし、ライオンの名前と年齢を表示するコードを書いてください。
    */
}

// Animal インターフェースを実装する Elephant クラスを定義
class Elephant(val name: String, val age: Int) : Animal {
    // makeSound メソッドの実装
    /*【穴埋め問題3】
    ここに makeSound メソッドをオーバーライドし、ゾウの鳴き声を出すコードを書いてください。
    */

    // displayInfo メソッドの実装
    /*【穴埋め問題4】
    ここに displayInfo メソッドをオーバーライドし、ゾウの名前と年齢を表示するコードを書いてください。
    */
}

// Animal を管理する Zoo クラスを定義
class Zoo {
    // 動物リストを保持するプロパティ
    private val animals: MutableList<Animal> = mutableListOf()

    // 動物を追加するメソッド
    fun addAnimal(animal: Animal) {
        animals.add(animal)
        // 動物が追加されたメッセージとその情報を表示
        println("動物が追加されました。")
        /*【穴埋め問題5】
        ここに追加された動物の情報を表示するコードを書いてください。
        */
    }

    // すべての動物情報を表示するメソッド
    fun displayAllAnimals() {
        println("すべての動物の情報:")
        /*【穴埋め問題6】
        ここに for 文を使って、すべての動物の情報を表示するコードを書いてください。
        */
    }
}

// メイン関数
fun main() {
    // Zoo のインスタンスを作成
    val zoo = Zoo()

    // Lion と Elephant のインスタンスを作成
    /*【穴埋め問題7】
    ここに Lion クラスと Elephant クラスのインスタンスを作成するコードを書いてください。
    */

    // 動物を追加
    /*【穴埋め問題8】
    ここに動物を Zoo に追加するコードを書いてください。
    */

    // すべての動物情報を表示
    zoo.displayAllAnimals()

    // 各動物の鳴き声を表示
    /*【穴埋め問題9】
    ここに各動物の鳴き声を表示するためのコードを書いてください。
    */
}

この問題の穴埋めコードは以上です。

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

練習問題の解答例と解説

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

// インターフェース Animal を定義

interface Animal {
    // 動物の鳴き声を出すメソッド
    fun makeSound()
    // 動物の情報を表示するメソッド
    fun displayInfo()
}

// Animal インターフェースを実装する Lion クラスを定義
class Lion(val name: String, val age: Int) : Animal {
    // makeSound メソッドの実装
    override fun makeSound() {
        println("$name が吠えました: ガオー!")
    }

    // displayInfo メソッドの実装
    override fun displayInfo() {
        println("ライオン - 名前: $name, 年齢: $age 歳")
    }
}

// Animal インターフェースを実装する Elephant クラスを定義
class Elephant(val name: String, val age: Int) : Animal {
    // makeSound メソッドの実装
    override fun makeSound() {
        println("$name が鳴きました: パオーン!")
    }

    // displayInfo メソッドの実装
    override fun displayInfo() {
        println("ゾウ - 名前: $name, 年齢: $age 歳")
    }
}

// Animal を管理する Zoo クラスを定義
class Zoo {
    // 動物リストを保持するプロパティ
    private val animals: MutableList<Animal> = mutableListOf()

    // 動物を追加するメソッド
    fun addAnimal(animal: Animal) {
        animals.add(animal)
        // 動物が追加されたメッセージとその情報を表示
        println("動物が追加されました。")
        animal.displayInfo()
    }

    // すべての動物情報を表示するメソッド
    fun displayAllAnimals() {
        println("すべての動物の情報:")
        for (animal in animals) {
            animal.displayInfo()
        }
    }
}

// メイン関数
fun main() {
    // Zoo のインスタンスを作成
    val zoo = Zoo()

    // Lion と Elephant のインスタンスを作成
    val lion = Lion("レオ", 5)
    val elephant = Elephant("エリー", 10)

    // 動物を追加
    zoo.addAnimal(lion)
    zoo.addAnimal(elephant)

    // すべての動物情報を表示
    zoo.displayAllAnimals()

    // 各動物の鳴き声を表示
    lion.makeSound()
    elephant.makeSound()
}

正解コードの解説

このコードは「動物園管理システム」を題材に、Kotlinのインターフェースやクラスを使ったオブジェクト指向プログラミングを学ぶ内容です。

それでは各部分をブロックごとに分解して詳しく見ていきましょう。

インターフェースの定義

interface Animal {
    fun makeSound()
    fun displayInfo()
}
  • interface: Kotlinではインターフェースをinterfaceキーワードで定義します。
  • メソッドの宣言: makeSounddisplayInfoは抽象メソッドです。具体的な処理はここでは定義されず、実装するクラスがそれを担います。

Lion クラスの定義

class Lion(val name: String, val age: Int) : Animal {
    override fun makeSound() {
        println("$name が吠えました: ガオー!")
    }
    override fun displayInfo() {
        println("ライオン - 名前: $name, 年齢: $age 歳")
    }
}
  • class Lion: ライオンを表すクラス。
  • Animal の実装: Lion クラスは Animal インターフェースを実装(:を使用)しています。
  • override: インターフェースで定義されたメソッドを具体的に実装する際に使用します。

Elephant クラスの定義

class Elephant(val name: String, val age: Int) : Animal {
    override fun makeSound() {
        println("$name が鳴きました: パオーン!")
    }
    override fun displayInfo() {
        println("ゾウ - 名前: $name, 年齢: $age 歳")
    }
}
  • class Elephant: ゾウを表すクラス。
  • Animal の実装: Elephant クラスも Animal を実装し、ゾウに特化した動作を提供します。

Zoo クラスの定義

class Zoo {
    private val animals: MutableList<Animal> = mutableListOf()
    fun addAnimal(animal: Animal) {
        animals.add(animal)
        println("動物が追加されました。")
        animal.displayInfo()
    }
    fun displayAllAnimals() {
        println("すべての動物の情報:")
        for (animal in animals) {
            animal.displayInfo()
        }
    }
}
  • Zoo クラス: 動物園を管理するクラス。
  • MutableList<Animal>: 動物のリストを管理します。Animal型を指定することで、動物として扱えるオブジェクトだけをリストに追加できます。
  • addAnimal: 動物をリストに追加しその情報を表示します。
  • displayAllAnimals: リスト内のすべての動物の情報を表示します。

メイン関数

fun main() {
    val zoo = Zoo()
    val lion = Lion("レオ", 5)
    val elephant = Elephant("エリー", 10)

    zoo.addAnimal(lion)
    zoo.addAnimal(elephant)

    zoo.displayAllAnimals()

    lion.makeSound()
    elephant.makeSound()
}
  • val zoo = Zoo(): 動物園のインスタンスを作成します。
  • LionElephant: 動物のインスタンスを作成します。
  • addAnimal: 動物園に動物を追加します。
  • displayAllAnimals: すべての動物の情報を表示します。
  • makeSound: 各動物の鳴き声を表示します。

まとめ

このコードではKotlinのインターフェースを使用してオブジェクト指向プログラミングの基礎を学びました。

インターフェースを利用することで異なる種類のオブジェクトを統一的に扱えるようになり、拡張性や柔軟性が高まります。

特に「インターフェース」と「実装クラス」の関係を理解することは、より高度なプログラミングスキルを身に付ける第一歩です。

ぜひ、他の動物クラスを追加して、このシステムをさらに拡張してみてください!

<<前のページ Kotlin記事一覧 次のページ>>

この記事への質問・コメント

この記事を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    Kotlinのテキスト&問題集トップへ戻る
    トップページへ戻る