こんにちは!なるーらぼです!前回はクラスについてお話ししました。今回は前回の最後で登場した抽象クラスに似ていますが用途が異なるインターフェースとその実装について、そしてクラスの継承についてみていきたいと思います。
継承とは
オブジェクト指向では頻繁に登場する「継承」ですが、これも掻い摘んでいうと「決めたことを拡張する」ということです。
そのため、利用するキーワードも「extends」というものを使います。これ、日本語で「広げる」という意味ですから:)
それでは継承してみますか。まずは前回も登場したロボットさんを登場させます。
class Robot{
String name
String bodyColorString speech(){
"コンニチハ"
}
void walk(){
println "ウィーーーン"
}
}
このロボットを機能拡張してファイヤロボットさんをつくってみます。でもベースはロボットさんです。
class FireRobot extends Robot {}
def f = new FireRobot(name: "nalulabo", bodyColor: "red")
println f.speech()
これをロボットさんのクラス定義があるのと同じファイルへ記述して実行してみてください。ファイヤロボにはなにも定義が記述されていないのに、ロボットさんと同じコンストラクタで実体化して「コンニチハ」と話したと思います。
これは「extends」キーワードでロボットさんを拡張したクラスですという宣言をGroovyに対してしているからです。もちろん機能を拡張しても構いません。「話す」機能に付け足ししましょうか。
class FireRobot extends Robot {
String speech(){
"${super.speech()}、ファイヤロボデス!"}
}
これで話してもらうと「コンニチハ、ファイヤロボデス!」と話したと思います。ご覧のとおり、機能が拡張されています。
ところでコード中に出てきた「super」というやつは何者なのでしょうか?これはベースになっているクラスを示しています。ですからこの「speech」メソッドはRobotクラスに定義されたspeechメソッドを包含した文字列を返すように拡張されたわけです。
こうした機能の上書きを「オーバーライド」と呼びますが「overwrite」ではありません。「override」です。
どちらかというと「無視する」という意味になり、ベースにしたものが持つ機能を「無視して別の機能にする」ということでしょう。
インターフェース
それでは次はクラス、特に抽象クラスとよく似た雰囲気を持ちますがインターフェースです。インターフェースはプロパティや実装を持たずに「それが何をすべきなのか」だけを羅列するものです。
例えばマウスもキーボードもボタンを持っていますよね。これらは実際の機能が大きくことなりますが、いずれも「押す」ことができます。こういったものをインターフェースと呼びます。
ではまたもやロボットさんに登場してきてもらいます。ロボットさんは元々、話す機能がなくても構いません。しかし「話す」機能が実装されていれば、きっと「コンニチハ」してくれるのではないでしょうか。
interface Speaker {
String speech()
}class Robot implements Speaker {
String name
String bodyColor
String speech(){
"コンニチハ"
}
void walk(){
println "ウィーーーン"
}
}
def f = new Robot(name: "nalulabo", bodyColor: "green")
println f.speech()
インターフェースを実装するには「implements」キーワードでインターフェース名を記述して実装することを表明します。「話すやつ」というインターフェースを実装したロボットさんはどのように「話す」のかが記述されました。だから「コンニチハ」とできます。
このインターフェースを実装したものは、必ずその機能が何なのかを記述しなければなりません。ですからもしロボットではなく自動車クラスだったとしても、このインターフェースを実装したら「speech」メソッドがどんな働きなのかを記述して決めてあげる必要があります。
さらに、インターフェースも継承をすることができます。どんな働きがあるのか、ということを付け足しすることができるわけです。
ではSpeakerインターフェースを継承して、さらに「話すし歩くやつ」というインターフェースを作成して、これを実装したロボットさんをつくってみましょう。
interface Speaker {
String speech()
}interface SpeakingWalker extends Speaker {
void walk()
}
class Robot implements SpeakingWalker {
String name
String bodyColor
String speech(){
"コンニチハ"
}
void walk(){
println "ウィーーーン"
}
}
def f = new Robot(name: "nalulabo", bodyColor: "green")
println f.speech()
f.walk()
ロボットさんは「話すし歩くやつ」というインターフェースしか実装していませんが、それは「話すやつ」インターフェースを機能拡張しているからこそ、speechメソッドもwalkメソッドも利用することができます。ですから同様に自動車クラスがこのインターフェースを実装したら同じようにする必要があります。
なお、1つ決まり事があります。インターフェースのもつメソッドは継承先からしか参照できない「protected」、それから自分からしか参照できない「private」というアクセス修飾子をつけることができません。それはそうですよね、だって中身は実装先のクラスで定義するのですから何があるかわからないとどうにもなりませんしね。
最後に
今回は継承、インターフェースとその実装についてみてきました。
次回はオブジェクト指向の延長線上にあるトレイトについてみていくことにしましょう。
0コメント