今回はトレイトについて語ってみるよ。
トレイトがわかると実装の可能性が広がるから、やってみよう!
Scalaのトレイト
まずは トレイト の感じを掴んでみYO!
色々な意見があるかもしれないけど、トレイトをこういうモノだと思っている。
機能を切りだして、再利用可能な塊にしたモノ
トレイトはJavaのインタフェース(interface)に近いモノという説明もある。
確かに、Javaのインタフェースのように使えると思うんだけど
なんかスッと入ってこないんだよね。
まだまだScalaの修業が足りないせいかもしれない。
トレイトの特徴
Scalaのトレイトには、以下な大きな特徴があるよ。
- traitキーワードで定義
- クラスパラメータを取ることができない
- メソッドを実装できる
- クラスや他のトレイトにミックスインできる
- 任意の数をミックスインできる
- 純粋ではないが多重継承ぽさがある
この特徴に沿って説明してみるね。
traitキーワードで定義
早速トレイトを定義してみよう。
scala> trait Job
defined trait Job
なんと、これだけでJobというトレイトが定義できてしまった。
トレイトを作ることはもう簡単だね!
クラスパラメータを取ることができない
クラスは以下のようにクラスパラメータを定義できるよね?
scala> class Job(name: String)
defined class Job
同じことをトレイトでやってみると
scala> trait Job(name: String)
<console>:1: error: traits or objects may not have parameters
trait Job(name: String)
^
コンパイルエラーが発生してしまうんだ。
これってつまりは、パラメータによる初期化ができないってことなんだよね。
でもこんな感じで、パラメータを受け取って初期化できるよ。
scala> trait Job { val name: String }
defined trait Job
scala> new Job { val name = "student" }
res0: Job = $anon$1@518677ee
scala> res0.name
res1: String = student
もう1つ。
scala> trait Job { val name: String }
defined trait Job
scala> new { val name = "student" } with Job
res2: Job = $anon$1@701ce28a
scala> res2.name
res3: String = student
メソッドを実装できる
次にメソッドを追加してみるよ。
trait Job {
def getName() {
"student"
}
}
どう?Javaのインタフェースでは、getName
メソッドのように実装を持つことはできないよね。
もうこの時点でJavaのインタフェースとの違いが出てきていました。
これが、機能を切り出すために実現されているコトの1つだよ。
クラスや他のトレイトにミックスインできる
トレイトを使うところを見たい!ってなってきていますよね?
今度は、トレイトを使ってみるよ。
ここで ミックスイン が出てくるんだ。
ミックスイン
ミックスインとは、 複数のトレイトを使ってクラスやトレイトを定義する ことだ。
このことを ミックスイン合成 なんて言うこともある。
Javaのインタフェースで言うと、 複数のインタフェースを実装してクラスを定義する みたいな。
クラスやトレイトを定義するために 使用したトレイト のことをミックスインと言うこともある。
この辺、言語によっても違うみたいだし、捉え方によっても違うから難しいところだけど、
ここでは上記のような整理にするよ。
ミックスインしてみる
やってみるよ!
object Trait1 {
def main(args: Array[String]){
val man = new Man
man.say()
}
}
trait Human {
val name = "飛行帽"
def sayName() {
println("My name is " + name)
}
}
class Man extends Human
ここでは、HumanトレイトをミックスインしてクラスManを作っている。
ここではミックスインする時に、extends
を使っている。
実はextends
かwith
キーワードでミックスインする。
-
extends
の場合は、他のクラスを継承しない場合に使用する。指定したトレイトのスーパークラスが暗黙の継承クラスとなる。スーパークラスが存在しない場合は、AnyRef
クラスとなる。1つしか指定できないため、その他のトレイトはwith
で指定する。 -
with
の場合は、extends
を指定済みで、他のトレイトを指定する場合に使用する。
任意の数をミックスインできる
もう先に書いたけど、with
キーワードを使って複数のトレイトをミックスインすることもできるんだ。
object Trait2 {
def main(args: Array[String]){
val man = new Man("虎丸龍次", "男塾", "一号生")
man.say()
}
}
trait Human {
val name: String
}
trait Job {
val job: String
}
trait Grade {
val grade: String
}
class Man(n: String, j: String, g: String) extends Human with Job with Grade {
val name = n
val job = j
val grade = g
def say() {
println("名前は" + this.name + "じゃ。" + job + grade + "じゃ。")
}
}
純粋ではないが多重継承ぽさがある
Scalaの継承は、単一継承のみで多重継承はサポートしていないんだ。
でもトレイトを使うと、多重継承ぽくできるみたいなんだ。
ここはゴメンナ。
実は多重継承をやったことないから、イメージがわかないんだ。
まとめ
今回は、 トレイト について語ってみたけど、掴むことができたかな?
もちろんトレイトにもまだまだ色々あるから調べてね。
トレイトを使いこなすには、モデリングとデザインの部分も重要だと思うよ。
今回も
体で感じてくれたかな?