Upload
yuta-shimakawa
View
260
Download
0
Embed Size (px)
DESCRIPTION
社内のLT大会でScalaについてお話するということで、Scalaのオブジェクト指向要素の中核であるところのTraitについて。
Citation preview
Trait in Scala
2014/05/08 Livesense SICP読書会LT大会
Scala
blog.enfranchisedmind.com/2009/05/scala-not-functional/
Scala
Java8
• interfaceのデフォルト実装
• ラムダ式
• 高階関数
• 型推論の強化
• 並列性の強化(並列コレクション、CompleteFuture)
• 遅延評価
• Stream
• Optional
• etc http://www.infoq.com/jp/articles/java-8-vs-scalahttp://news.mynavi.jp/special/2014/java8/
それでもScala を使いたいか?
こんな資料作るくらいだからわかりますよね?
本日のテーマ 『トレイト』
なぜトレイトを とりあげるか?
• トレイトはScalaのオブジェクト指向言語としてのハイライトの一つだと思う。
• ActorやらFutureやらを使った並行性制御の利点は多いけど、多くの職業プログラマが直面する課題は、OOPを使ったソフトウェア課題の解決にあるのではないかと思う。
• ということで、Scalaの言語紹介としてトレイトから取り上げてみる。
$ scalascala> “trait”.translate(“ja_JP”)res0: List[String] = List(特性, 特徴, 特色)
http://ejje.weblio.jp/content/trait
トレイトとは?
クラスのように、メソッドとフィールドの定義をカプセル化したもので、Scalaにおけるコード再利用の基本単位(コップ本より)
trait Philosophical { def philosophize() { println(“我思う故に我あり”) }}
クラスにミックスイン• 抽象メンバーだけを宣言して、ミックスインするクラスでの実装を強制
• 実装を定義することもできる
• 複数のトレイトを同時にミックスインすることもできる
• ミックスインしたメソッドをオーバーライドしたり、super呼び出しすることもできる
trait A { def f() // 抽象メソッド}!trait B { def foo() = println("foo")}!trait C { def bar() = println("bar")}!class D extends A with B with C { def f() = foo() // 抽象メソッドを実装&トレイトBのfooを呼び出し override def bar() = { // トレイトCのbarメソッドをoverride super.bar() // トレイトCのbarメソッドを呼び出し println("BAR") }}
インスタンス生成時に ミックスイン
class Japanese!
trait Kansai!
trait Kanto!
val me = new Japanese with Kansai with Kanto
super呼び出しの線形化
class Animal!
trait HasLegs extends Animal!
trait FourLegged extends HasLegs!
trait Furry extends Animal!
class Cat extends Animal with Furry with FourLegged
Animal HasLegs
Furry FourLegged
Cat
class Cat extends Animal with Furry with FourLegged
Cat -> FourLegged -> HasLegged -> Furry -> Animal with Furry with FourLegged
線形化
積み重ね可能な変更
abstract class IntQueue { def put(x: Int) def get(): Int}!import scala.collection.mutable.ArrayBufferclass BasicIntQueue { private val but = new ArrayBuffer[Int] def put(x: Int) = but += x def get() = but.remove(0)}!trait Doubling extends IntQueue { abstract override def put(x: Int) = { super.put(2 * x) }}!trait Filtering extends IntQueue { abstract override def put(x: Int) = { super.put(x.abs) }}
val q1 = new BasicIntQueueq1.put(10)q1.get() // Int = 10!
val q2 = new BasicIntQueue with Doublingq2.put(10)q2.get() // Int = 20!
val q3 = new BasicIntQueue with Doubling with Filteringq3.put(-10)q3.get() // Int = 20
『Scalaスケーラブルプログラミング』12章より
AOPっぽいことも可能
参考) http://d.hatena.ne.jp/j5ik2o/20101103/1288752727
trait Executor { def execute(): Unit}!trait LoggableExecutor extends Executor { def log(() => Unit):Unit = … abstract override def execute(): Unit { log { super.execute } }}!class SomeExecutor extends Executor { def execute(): Unit = …}!val e = new SomeExecutor with LoggableExecutore.execute
自分型アノテーション
trait A { def foo() = “foo”}!
trait B { def bar() = “bar”}!
trait C { this: A with B => def f() = foo + bar}!
val c = new C with A with Bc.f // String = foobar
Trait Cのインスタンスを生成するにはAとBをミックスインしなければならない。CからAとBへの依存性を明示することができる。
Cake PatternでDI
class User!trait UserRepositoryComponent { val repos: UserRepository trait UserRepository { def findById(id: Int): User }}!class UserService { this: UserRepositoryComponent => def findById(id: Int): User = { repos.findById(id) }}
trait MySQLUserRepositoryComponent extends UserRepository Component { val repos = new MySQLUserRepository class MySQLUserRepository = { def findById(id: Int): User = … }}!val userService = new UserService with MySQLUserRepositoryComponent!val user = userService.findById(1)
注)cake pattern については問題点も指摘されているので注意
まとめ
トレイト使うとOOPが気持ちよくなる。かもね。