はじめに
SOLID 原則の 4 つ目は ISP(インターフェース分離の原則) です。
これは 「大きすぎるインターフェースを分割し、利用者に不要な依存を強要しない」 という考え方で、クリーンな設計を維持するうえで欠かせません。
1. 定義
インターフェース分離の原則(ISP) とは:
クライアントは、自分が使わないメソッドに依存してはならない。
2. 直感的な例
ISP 違反(インターフェースが肥大化)
interface Worker {
fun work()
fun eat()
fun sleep()
}
class Robot : Worker {
override fun work() { println("Working...") }
override fun eat() { throw UnsupportedOperationException("Robot doesn't eat!") }
override fun sleep() { throw UnsupportedOperationException("Robot doesn't sleep!") }
}
- ロボットは「食べる」「寝る」を持たないのに、無理やり実装させられている
- 利用側も「本当にこのメソッド使えるの?」と混乱する
ISP 準拠(役割ごとに分離)
interface Workable { fun work() }
interface Eatable { fun eat() }
interface Sleepable { fun sleep() }
class Human : Workable, Eatable, Sleepable {
override fun work() = println("Working...")
override fun eat() = println("Eating...")
override fun sleep() = println("Sleeping...")
}
class Robot : Workable {
override fun work() = println("Working...")
}
- クライアントは必要なインターフェースだけ依存できる
- 依存の最小化が実現
3. Flutter / Android での例
Flutter
// NG: 1つのインターフェースに責務を詰め込みすぎ
abstract class Storage {
void save(String key, String value);
String load(String key);
void clearCache(); // 全クライアントが必要とは限らない
}
// OK: 責務ごとに分離
abstract class Savable {
void save(String key, String value);
}
abstract class Loadable {
String load(String key);
}
abstract class CacheClearable {
void clearCache();
}
→ Web用ストレージ、モバイル用ストレージなどで「必要な機能だけ」実装可能。
Android (Kotlin)
// NG
interface Printer {
fun print()
fun scan()
fun fax()
}
class SimplePrinter : Printer {
override fun print() { println("Printing...") }
override fun scan() { throw UnsupportedOperationException() }
override fun fax() { throw UnsupportedOperationException() }
}
// OK
interface Printable { fun print() }
interface Scannable { fun scan() }
interface Faxable { fun fax() }
class SimplePrinter : Printable {
override fun print() = println("Printing...")
}
4. ISP 違反のデメリット
- 実装クラスが不要なメソッドを抱える
- テスト対象が増えてコスト増
- 利用側が余計な知識を持たされる
- 抽象化の意味が薄れる
5. 実務での適用ポイント
-
インターフェースは「役割」で切る」
→Repositoryを「Readable」「Writable」に分割する - クライアント単位で最小限の契約を設計する
-
レビュー時に質問する
→ 「このクラスは、このメソッドを必ず実装する必要がある?」 -
Clean Architecture と組み合わせる
→ 各層のインターフェースはユースケースや役割単位で設計
6. まとめ
- ISP = 不要な依存を持たせない設計
- インターフェースは「大きなひとつ」ではなく「小さな役割の集合」
- 実装や利用がシンプルになり、テスト容易性・保守性・理解しやすさ が向上する