はじめに
- 最近、社内の開発チームで勉強会を実施したり情報共有したりといったことが盛んに行われるようになってきてとても意義深いなぁと思う今日のこの頃です
- 勉強会はテーマとなる本を決めて実施してまして、先日までは「Kotlinイン・アクション」という本を題材にしていました
- 私はKotlinのロゴが入ったトレーナーを着て仕事をしていますが、Kotlinに関してはいまのところペーペーですのでこの本に関する詳しい話はKotlinエキスパートのAndroidチームか未来のKotlinエキスパートである私に譲ることにして今の私がこの本を読んで(最初の5章まで)1番記憶に残ってることについて書ければと思います
4.1クラス階層の定義
- 4章「クラス、オブジェクト、インターフェイス」の最初のパートにあたり、Kotlinにおけるクラス・オブジェクト・インターフェースの言語仕様について書かれています
- 普段、主にPHPを書いてる私としては(実用性に疑問ありますが)インターフェースに具象メソッドの実装を含めることができたり、スーパークラスやインターフェースをオーバーライドする際にoverride修飾子が必須であるとか、とても新鮮な言語仕様になっており興味が湧いた部分でした
- 特に後者については「継承より委譲」というキーワードを昨今意識してるので(実践できているかは別として)、そのワードに関連の高い仕様だなと思っており特段、興味津々です
継承と委譲について
- 継承も委譲もオブジェクト指向プログラミングによる開発にてよく用いられる手法です
- せっかくなのでいま一度、継承と委譲について
継承
- よくある例ですがAnimal(動物)クラスをまずは作ります
- 動物は走るのでrun()メソッドを用意しました
- ※ 雑に走る速度を返します(単位すらわからないけど)
open class Animal {
val runningVelocity: Int
constructor(runningVelocity: Int) {
this.runningVelocity = runningVelocity
}
fun run(): Int {
return this.runningVelocity
}
}
- 動物といえば犬なのでDogクラスを作ります
- このクラスはAnimalクラスを継承して作りましたのでrun()メソッドが使えます
class Dog : Animal {
constructor() : super(10)
}
fun main() {
val dog = Dog()
println(dog.run())
}
// > 10
委譲
- つぎに動物といえば猫なのでCatクラスを作ります
- こちらは継承ではなく委譲のパターンでAnimalクラスのrun()メソッドを呼び出すようにしましょう
class Animal { /*...*/ } // 中身は一緒
class Cat {
val cat: Animal
constructor() {
this.cat = Animal(5)
}
fun run(): Int {
return this.cat.run()
}
}
fun main() {
val cat = Cat()
println(cat.run())
}
// > 5
継承より委譲を
- つぎ鯨とか鳥とか作るから泳いだり、飛んだりできるようにしなくちゃ、イルカとかシャチとか増えたら泳ぐし、コウモリとかも飛ぶよなぁ、(と継承することを前提としたAnimalクラスを拡張したところ)
open class Animal {
val runningVelocity: Int
val flyingVelocity: Int
val swimmingVelocity: Int
constructor(
runningVelocity: Int,
flyingVelocity: Int,
swimmingVelocity: Int
) {
this.runningVelocity = runningVelocity
this.flyingVelocity = flyingVelocity
this.swimmingVelocity = swimmingVelocity
}
fun run(): Int {
return this.runningVelocity
}
fun fly(): Int {
return this.flyingVelocity
}
fun swim(): Int {
return this.swimmingVelocity
}
}
- うーん、まぁ犬は泳げるけど飛ばないよなぁ、、、鯨も飛ばないし鳥は、、、まぁ泳ぐやつもいるか?(事実とそぐわないクラスができてしまった。。。)
Class | run() | fly() | swim() |
---|---|---|---|
Dog | ○ | ○ | ○ |
Cat | ○ | × | × |
Bird | ○ | ○ | ○ |
Whale | ○ | ○ | ○ |
- 上記は極端な例でしたが、継承を使うことによって、使う想定のないメソッドが使えてしまうことはとても危ういものです
- ただ継承は強力ですし、継承の方が適してる場面もあると思うので要は使い所で継承にせよ委譲にせよ、クラスの関係性などしっかりと見極めた上で使うようにしよう・心がけたいというところが一番大事かなと思っております
おわりに
- 普段使ってない言語(Kotlin)について言語仕様を知ったり、普段からその言語に触れているAndroidのエンジニアと議論できたことがとても新鮮な機会だったと思い、主催してくれたAndroidメンバーにはとても感謝しています
- 来週からは新しい書籍を元に勉強会開催するのでそこで得たことも活かしていければと感じました