Kotlin開発で使用されるクラスの種類
- class
- data class
- object
- companion object
- enum class
- abstract class
- interface
- sealed class
data class
- APIレスポンス・データ保持に最適
- equals(), toString(), copy()メソッドが自動作成される
- データ保持が目的なので、処理をたくさん書かないようにする
- 自動的にfinalで作成されるので他のクラスから継承することができない
- 値の等値性やコピー機能などの「一貫したふるまい」を守るため
APIレスポンスを定義
data class UserResponse(val name: String, age: Int, email: String)
UIの状態を表現するとき
data class UiState(
val isloading: Boolean = false,
val errorMessage: String? = null,
val data: List<String> = emptyList()
)
copy()
を使用して簡単に状態を更新できる。
state = state.copy(isLoading = true)
object
- シングルトン(唯一のインスタンス)を定義するための仕組み
- newや()でインスタンスを作成する必要がなく、一度作成されたインスタンスがどこからでも使える
- Loggerや定数、設定などの共通処理をobject化すると便利
- インスタンスが一つしか作成されないのでメモリ効率がいい
- シングルトンパターンを自動で定義
ユースケース
// ログ出力を共通化
object Logger {
fun log(message: String) {
println("ログ: $message")
}
}
// 定数や設定をまとめる
object AppConfig {
const val VERSION = "1.5.0"
const val API_URL = "https://api.example.com"
}
呼び出すときはインスタンス化をしなくてもそのまま使うことができる!
ログを呼び出す
Logger.log("ログを出力する)
companion object
- クラスのインスタンスを作らなくても使える静的な仲間
- クラスに属しながら、インスタンス化せずに呼び出しできる関数や定数を定義
- ファクトリメソッド(オブジェクトの作り方を自分で定義)
- 定数をまとめたいとき(javaのstatic final stringの代わりになる)
- インターフェースの中でstaticな関数を定義したいとき
- シリアライザーやコンバーターを定義する場所として使う
ゲストユーザーを作成
class User(val name: String) {
companion object {
fun createGuest(): User {
return User("ゲスト")
}
}
}
val guest =User.createGuest()
User()でインスタンスを作成しなくても、createGuest()を呼び出すことができる
objectとどう使い分けるか?
比較項目 | object | companion object |
---|---|---|
どこにあるか | クラスの外(単体で存在) | クラスの中にある |
用途 | アプリの共通の処理・設定 | クラスに関係するstatic的な処理・定数 |
名前 | 自由につけられる | デフォルトでcompanion
|
Javaとの互換 | 不向き(Javaから使いにくい) | @JvmStaticでstatic関数化できる |
enum class
- 「限られた定数の集まり」を表すクラス
- 書き間違いやタイポがなく定義されたものしか使えないので安心
- 曜日、月、性別、状態などの選択肢が限られていて固定の場面に最適
- whenとの相性がいい
- プロパティや関数を持して拡張できる
性別を表す
enum class Gender {
MALE,
FEMALE,
OTHER
}
使い方
val gender = Gender.MALE
if(gender == Gender.MALE) {
println("性別は男性です")
}
abstract class
- 抽象的なクラスを作成することができる
- 共通の性質やふるまいをまとめるための土台クラスで自分だけでは完成しないクラス
- インスタンス化はできない
- 継承されることが前提で子クラス内で具象化するのが前提
- interfaceと違って、実装も持てる
- 共通処理(実装)をまとめるベースクラス
- コンストラクタを持てる
abstract class Car {
abstract fun stop() //ここでは実装をしない。子クラスで実装する
}
サブクラスでの実装例
class SportsCar: Car() {
override fun stop() {
println("車が止まりました")
}
}
interface
- 「これができるクラスになってね!」というルールや契約を定義する仕組み
- 処理の中身は書かない or 最小限だけ
- インターフェースを実装したクラスは、そのルールに従わなければいけない
- 共通のふるまいをインターフェースにすることで、依存関係を減らせる
インターフェースを定義する
interface Clickable {
fun onClick()
}
class Button : Clickable {
override fun onClick() {
println("ボタンがクリックされました")
}
}
異なるクラスに「共通の機能」をつけたいときに使用する。実装方法はバラバラだけど「クリックできる機能は持っているよ」と統一することができる
sealed class
- 限られた種類だけが使える、拡張されたenumのようなクラス
- 親クラスとして使われ、継承できる子クラスは「あらかじめ決めておく」ことが前提
- whenでの分岐が安全にかける
- data classやobjectを組みあわせるのが定番
- 定義した全てのパターンを網羅しないとエラーが出る
- UIの状態管理、APIレスポンスの結果を安全に表現できる
sealed class Result
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading: Result()
data class
やobject
と組み合わせるのが定番
whehで安全に分岐できる
fun handle(result: Result) {
when (result) {
is Success -> println("成功:${result.data}")
is Error -> println("エラー:${result.message}")
is Loading -> println("読み込み中…")
}
}