- 基本は迷ったら trait にしておけば良いと思います
- trait は一つの class に複数 mixin できますが、class は一つしか継承できません
- つまり、trait であれば mixin される class を気にしなくてよいですが、 abstract class にした場合は、extends される class が他に継承したい物が無いか気にする必要があります
- trait はコンストラクタを持つ事ができませんが、abstract class はコンストラクタを持つ事ができます
- 従って、型引数に制約をつけたい時や、共通のフィールドの初期化などがある場合は、abstract class にすると楽な場合があります。
- 以下に具体例を示します。良くある Java の enum を Scala で定義する場合の例です。
Last active
June 19, 2023 12:53
-
-
Save gakuzzzz/10081860 to your computer and use it in GitHub Desktop.
trait と abstract class の使い分け
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public enum UserType { | |
ADMIN("管理者"), | |
REGULAR("一般会員"), | |
GUEST("ゲスト"); | |
private final String label; | |
UserType(final String label) { | |
this.label = label; | |
} | |
public String getLabel() { | |
return label; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// trait で表現した場合 | |
sealed trait UserType { | |
val label: String | |
} | |
object UserType { | |
case object Admin extends UserType { | |
val label = "管理者" | |
} | |
case object Regular extends UserType { | |
val label = "一般会員" | |
} | |
case object Guest extends UserType { | |
val label = "ゲスト" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// abstract class で表現した場合 | |
sealed abstract class UserType(val label: String) | |
object UserType { | |
case object Admin extends UserType("管理者") | |
case object Regular extends UserType("一般会員") | |
case object Guest extends UserType("ゲスト") | |
} |
- trait が持てないのはコンストラクタであって、Javaで言うところのインスタンスイニシャライザは持つ事ができます。
- trait の具体例にある通り、Scala では field も override することができます。
- Java では override にならず hidding になります。
- Java ではポリモーフィックに動作するのはインスタンスメソッドだけでしたが、 Scala では全てのメンバがポリモーフィックに動作します。
sealed
という予約語をつけると、同一ファイル内でしかサブクラス(あるいはmixinされたクラス)を定義できなくなります。- enum の様な列挙しきれる事が期待されるものに使います。
- sealed を付けておく事で、パターンマッチの際に全てのパターンを網羅したかコンパイラがチェック可能になります。
- ちなみに Java では一つのファイル内に public なものは一つしか書けませんでしたが、 Scala では一つのファイルに複数の public なものを書けます。
- trait はバイナリ互換性を保ちにくいのでなるべく abstract class にみたいな議論もあります。
- 現状、バイナリ互換性を保ちにくいのは事実ですが、JavaSE8 から入った interface の default method では バイナリ互換性が維持できる ので 今後 Scala側で Java8 対応が進めば解決していくのではないかと個人的には思っています(というか期待してます)
- 現状では最終的に生成されるバイトコードが trait の方が多くなります。
- この辺も Java8 対応で変わる可能性があります。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment