19.0430
インターフェイス(interface)
インターフェイスとは、抽象クラス と、似ています。
が、違うところも、あります。
まだ、インターフェイス とは、なんなのだ、という話もまだなのに、
とりあえず、違いから見ていきましょう。
インターフェイスとは何か、に関しては、実際にコードを見ながら見ていきます。
インターフェイス と、抽象クラス の違い
1. プロパティは、実装できない。
抽象クラスの場合、メソッド も、プロパティ も、実装出来ます。
(実装できるとは、プロパティ の場合は、値を決めたコードを書くこと.
メソッドの場合は、{ 具体的なコード } を、書くこと.)
ただし、最低1つは、abstract な プロパティ か メソッド を、書くこと。
しかし、インターフェイス のばあい、メソッドは、実装出来ますが、
プロパティは、実装出来ません。
2. 多重継承ができる
多重継承 とは、「2つ以上のクラスから、継承すること」 です。
interface は、それが出来るのですが、interface は classではないからです。
class を使った、多重継承 は、出来ません。
interface は、class では、ありませんが、構造的に見たら、class とも言えそうです。
ただ、実装されている部分が、少ないので、継承先に、
「やり過ぎる/余計なプロパティ・メソッドを付け加える」ことは、ありません。
それで、多重継承の問題点である、「複雑になりすぎる」 ことから逃れられます。
では、どんな時に、多重継承 したいでしょうか?
これは、ゲームの世界でしかありえないでしょうが、
たとえば、「空飛ぶくらげclass」 と、「空飛ぶ車class」 を作るとします。
この場合、「くらげclass」 と 「車class」 のそれぞれに、「空飛ぶ機能」 を、実装するより、
「空飛ぶinterface」 を、実装/継承という言葉は使いません した方が、
効率的かもしれません(interface は、メソッドを実装出来ます)。
また、「空飛ぶくらげclass」 と 「空飛ぶ車class」 と 「空飛ぶ猫class」 であれば、
これはもう、「空飛ぶinterface」 を、実装した方が、まず、効率的でしょう。
そればかりでなく、実装したクラスの 構造/仕組み も、よりクリアになるでしょう。
interface を、実装したコード例
そこで、こんなコードを書いてみました。
このコードの概要:
まず、何をするのか?は、
紹介
鳴く
を、ねこ、いぬ、きつね に、やっていただきます。
それで、
抽象class Animal をつくり、Cat/Dog/Foxクラス を、継承して作ります。
インターフェイスmakeSound を、それぞれのclassに、実装します。
/ これは、楽器でも、人間でも、一応は使えます。
こんなところですが、このコードのポイントは、
1. 抽象class の、継承(Animal ⇐ Cat/Dog/Fox)
2. それによって、多態性が、使える(introduceAndShout(a: Animal)関数)。
3. MakeSoundインターフェイス の実装
このコードに関して、新しい部分は、
interface の、実装方法
だけです。
ですので、簡単に見ていきます。
2~18行目:
インターフェイスMakeSoundの定義
プロパティ は、実装出来ません:
val sound: String(音のStringインスタンス)
val howMany: Int(何回、音を発するか、Int型)
/ interface は、必ず実装します、、openキーワード は、不要です。
メソッドは、実装します。
このコードの場合は、ここで実装しておいた方が、楽です。
makeSound(sound: String, howMany: Int)
/ プロパティ、sound・howMany を使って、sound を、howMany回、発します。
20~22行目:
抽象class Animal の定義
プロパティ を、abstract にする。
abstract val kind: String(kind:動物の種類、String型)
この場合、各クラスに、含めた方が、簡単な気もしますが、
この利点は、この親class を、作っておくと、多態性を使うとき、Animal型 として使えます。
24~38行目、40~48行目、50~58行目:
それぞれ、Cat/Dog/Foxクラス を、
抽象クラスAnimal、インターフェスmakeSound
の、overrideすべきを、実装します。
introduce()メソッド は、それぞれ、新たに書いています。
/ これは、同じ内容なので、抽象class で、実装しておくべきでした。
/ まあでも、こんな(軽い)失敗例も、見ておくことは、勉強になりますね。
/ つまり、Animalクラス で、実装しておけば、3回も同じことを書かなくて済みます。
makeSound()メソッド は、インターフェイスMakeSound のを、そのまま使いますので、
何も書かなくても、実装されます。
インターフェイスの実装方法 は、抽象クラス の、場合と違って、
コンストラクタ/() は、付けません!
ここには、注意してください。
class Cat(val name: String, val color: String) : Animal(), MakeSound
また、2つ目の実装からは、, で、区切ってください。
61~63行目:main()関数:
Cat/Dog/Foxクラス のインスタンス、cat/dog/fox を、作っています。
65~85行目:main()関数:
Cat/Dog/Foxクラス の インスタンス、cat/dog/fox は、
Animal型 として、扱えるので(多態性)、
そのための、関数(classに属していないのでメソッドではない)
introduceAndShout(a: Animal)(紹介して 鳴く(叫ぶ))
を、作っています。
when文 を、使いました。
when式 では、else が、必須ですが、when文 の時は、なくても、OKです。
82~87行目:main()関数:
1. println() を使って、まず動物の種類を出力します。
cat.kind のようにして、それぞれのclassの、プロパティ に、アクセスし、
それを、文字列テンプレート に、まず返し、他の文字/: と、一緒に、コンソールに、出力します。
2. introduceAndShout(a: Animal)メソッド に、
実際の型(cat/dog/fox)(大雑把にAnimal型ではなくて)を、引数にして、実行しています。
3. 以上の「1.2.パターン」 を、3回行っています。
以上を踏まえて、コンソールへの出力がどうなるか、考えてください。
結果はこうなります。
まとめ
・ interface/インターフェイス では、メソッドは、実装出来ますが、
プロパティは、実装出来ません。
・ interface は、多重継承 が出来ます。(class/抽象class を、2つ以上、実装出来ません)
・ interface の、実装時、コンストラクタ は、付けません!
・ class に、2つ以上、実装する時は , で、区切ります。
・ interface での、プロパティ・実装されていないメソッド は、実装先のclass で、実装しなければならない。