もくじ
はじめに
ScalaMatsuriってけっこう関数型の発表が多く、オブジェクト指向の発表は少ない。オブジェクト指向の発表はあまりない。しかし、普段コードを書いているとオブジェクト指向の機能を使うことは多い。ので発表してみることにした。
DIの話が多め。
Scalaの言語の性質
Javaとくらべてどうか、ということを考えると以下の2店がある。
- immutable
- Composable
- traitとか
DDDの本を読むと、Java、しかも古いJavaの言語仕様を想定して書かれているので、Scala,にそのまま当てはめるのは微妙である。われわれもScalaをうまく使えるように進化していかなければならない。
class
Scalaのclass
case class
これはScala独自のもの
classとcase classどちらを使えばいい
初心者だと「case classでよくない?」となってしまうがそうとはいかない。case classの透過性だとおかしいって場合はcase classだとおかしい。
trait
Scala独自の機能
- Interfaceとして使われるのが一番多いのではないか
- Mixinにも使われる
- Cake pattern
- ケーキの材料を組み合わせて作るみたいな
- classの材料としてのtrait
object
- シングルトンとして使われる
- がシングルトンって本当はあんまりよくない
- Companion object
これらをどう使っていくか
これらを組み合わせてどうやってclassを作っていくか、というのが今回の話。
シングルトンだらけにしてはいけない
Scalaではobjectが乱用される傾向にある。serviceとかdaoとか。
objectにすると何がダメなのか
実装を差し替えられないというのが一番の欠点。使えば使うほど密結合になってしまう。
object UserRepository object UserService { def get = UserReposutiry.fetch }
ではどうするのか
DIをうまく使う
コンストラクタインジェクション
class UserRepository { } class UserService(userRepositiry: UserReposutory) { Def get = userRepository.fetch }
コンストラクタ引数が多くなるのは依存が複雑になっている合図。
Guiceを使ってコンストラクタインジェクション
class UserRepository { } class UserService @Inject (userRepositiry: UserReposutory) { Def get = userRepository.fetch } getInstance(UserService);
コンストラクタインジェクションの特徴
- シンプル
- GuiceをはじめとしてほとんどのDIコンテナが対応
- Play Framework との相性も良い
Cakeパターン
traitをいっぱい使ってクラスを作っていく
val userService = new UserService with UserRepository
case class
case class は別のクラスとかを持たない。
case class User(id: Int, name: String, repository: UserRepository) { }
UserRepositoryをもつと透過性的に問題が….。case classには振る舞いを持たせるべきではない。
振る舞いをもたせたい場合は?
implicitで定義する
case class User(id: Int, name: String) { } class UserOpts(userRepository: UserRepository) { Implicit def RichUser(user: User) { def get = userRepository.detch } }
まとめ
- 自分DI好きだな
- 何も考えずCakeパターン、何も考えずコンストラクタインジェクション、はだめ
- 疎結合にしよう