🎉
インターフェース分離の原則 (Interface Segregation Principle, ISP)
1. どんなもの?
インターフェース分離の原則(Interface Segregation Principle, ISP)は、クラスが利用しないメソッドを持つインターフェースに依存してはならないという設計原則です。
大きなインターフェースを小さな役割ごとに分割することで、クラスが必要な機能だけを実装するようにします。
例えば、あるクラスが「すべてのメソッドを実装しなければならない大きなインターフェース」に依存すると、余計なコードが増えたり、変更が難しくなります。この原則はそれを防ぎます。
2. 通常の実装方法と比べてどこがすごいの?
通常の方法
大きなインターフェースを持つ場合、必要ないメソッドも実装しなければならず、無駄が生じます。
# NOTE: Workerモジュールでインターフェースを定義する。code, test, deployの3つのメソッドを実装しなければならない
module Worker
def code
raise NotImplementedError
end
def test
raise NotImplementedError
end
def deploy
raise NotImplementedError
end
end
# NOTE: DeveloperクラスはWorkerモジュールをインクルードしているが、deployメソッドを実装していない
class Developer
include Worker
def code
puts "Writing code"
end
def test
puts "Testing code"
end
def deploy
raise "I don't deploy"
end
end
dev = Developer.new
dev.deploy # => エラー: I don't deploy
-
課題:
-
Developer
クラスはdeploy
メソッドを実装しないのに、インターフェースの制約上実装しなければならない。 - 必要のないメソッドを実装することで、コードが煩雑になる。
-
ISPに基づいた方法
インターフェースを分割することで、クラスが必要な機能だけを実装できるようにします。
module Coder
def code
raise NotImplementedError
end
end
module Tester
def test
raise NotImplementedError
end
end
class Developer
include Coder
include Tester
def code
puts "Writing code"
end
def test
puts "Testing code"
end
end
dev = Developer.new
dev.code # => "Writing code"
dev.test # => "Testing code"
-
利点:
- クラスは必要なメソッドだけを実装すればよい。
- 余計な依存がなくなり、コードが簡潔になる。
3. 技術や手法の"キモ"はどこにある?
-
役割ごとの分離
- インターフェースを小さな役割に分けることで、必要な機能だけを実装できます。
-
柔軟な設計
- クラスが複数のインターフェースを選択的に実装できるようにすることで、設計の柔軟性が向上します。
-
変更の影響を最小化
- インターフェースが小さくなれば、変更による影響範囲も小さくなります。
4. 実装例
例: Storageサービス
ローカルストレージやクラウドストレージ(S3やGoogle Cloud)を選択的に使用します。それぞれのストレージが異なるインターフェースを実装しています。
# NOTE: インターフェースを定義するStorageServiceモジュール
module StorageService
def upload(file)
raise NotImplementedError
end
def download(file)
raise NotImplementedError
end
end
class LocalStorage
include StorageService
def upload(file)
puts "Uploading #{file} to local storage"
end
def download(file)
puts "Downloading #{file} from local storage"
end
end
class S3Storage
include StorageService
def upload(file)
puts "Uploading #{file} to S3"
end
def download(file)
puts "Downloading #{file} from S3"
end
end
storage = LocalStorage.new
storage.upload("file.txt") # => "Uploading file.txt to local storage"
-
実装ポイント:
- 各ストレージは独自のロジックを持ちながら、共通のインターフェースを実装。
5. 議論はあるか?
メリット
- クラスが必要な機能だけを実装すればよいため、設計がシンプルになる。
- インターフェースが小さくなることで、変更の影響範囲を最小化。
- 再利用性が高まり、メンテナンスが容易になる。
デメリット
- インターフェースを分割しすぎると、管理するファイルやコードが増える。
- 小規模なプロジェクトでは過剰設計になる場合がある。
議論
インターフェース分離の原則は、特に大規模なシステムで有効ですが、小規模プロジェクトではコストが高くなる場合があります。適切な範囲で適用することが重要です。
6. まとめ
インターフェース分離の原則(ISP)は、クラスが利用しないメソッドを持つインターフェースに依存しないよう設計する原則です。
この原則を守ることで、コードの保守性と拡張性が向上し、柔軟でシンプルな設計を実現できます。
Discussion