はじめに
巨大クラス(Large Class) は、クラスに本来の責務以上の機能が詰め込まれた状態を指します。
「何でも屋クラス」になりやすく、変更時の影響範囲が広がり、テストや再利用性を著しく損ないます。
代表的な解決策は クラス抽出(Extract Class) や 責務分割(SRP: 単一責任原則) です。
8.1 巨大クラスの特徴
- フィールドやメソッドが過剰に多い(100行を超える長大クラス)
- 1つのクラスが複数の責務(UI処理、データ処理、ネットワーク処理など)を同時に担っている
- 命名が抽象的になりがち(
Manager,Helper,Utilなど) - 修正や拡張のたびにクラス全体に影響が及ぶ
8.2 解決手法
-
クラス抽出(Extract Class)
→ 関連するフィールドやメソッドを別のクラスに切り出す -
インターフェース抽出(Extract Interface)
→ 公開 API を分離し、依存関係を明確化 -
委譲(Introduce Delegation)
→ サブクラス化ではなく委譲を使って責務を小さく保つ -
デザインパターン活用
→ Strategy / Observer / Mediator などで関心事を分離
8.3 Kotlin 例
Before:巨大クラス
class UserManager {
// データ保持
private val users = mutableListOf<User>()
// ユーザー管理
fun addUser(user: User) { users.add(user) }
fun removeUser(user: User) { users.remove(user) }
// 永続化
fun saveToDatabase() { /* DB保存ロジック */ }
fun loadFromDatabase() { /* DB読み込みロジック */ }
// 認証
fun login(username: String, password: String): Boolean { /* 認証処理 */ return true }
fun logout(user: User) { /* ログアウト処理 */ }
// 表示
fun printUserList() {
users.forEach { println(it) }
}
}
After:責務ごとに分割
class UserRepository {
private val users = mutableListOf<User>()
fun add(user: User) = users.add(user)
fun remove(user: User) = users.remove(user)
fun list(): List<User> = users.toList()
}
class UserPersistence {
fun save(users: List<User>) { /* DB保存処理 */ }
fun load(): List<User> { /* DB読み込み処理 */ return emptyList() }
}
class AuthService {
fun login(username: String, password: String): Boolean { /* 認証 */ return true }
fun logout(user: User) { /* ログアウト処理 */ }
}
→ 単一責任ごとに分割 することで、変更の影響範囲が限定され、テストもしやすくなる。
8.4 実務での指針
- クラスは 1 つの責務に限定(SRP の原則)
- 100 行を超えるクラスは分割を検討
- 「Manager」「Helper」といった名前は注意信号
- Lint/静的解析(Detekt, SonarQube)で大きすぎるクラスを検出
- CI/CD で コードサイズのルール化 を導入する
まとめ
- 巨大クラス は変更コスト増・テスト困難の原因
- 解決には クラス抽出・インターフェース抽出・委譲 を活用
- 基本思想:1 クラス = 1 責務。責務分割でシンプルかつ拡張性の高い設計にする