SOLID原則のインターフェース分離の原則(ISP)についてRubyで解説
プログラミング #ruby #SOLID #オブジェクト指向 #クリーンコードオブジェクト指向プログラミングにおいて、コードの保守性、可読性、再利用性を高めるために、SOLID原則と呼ばれる5つの重要な設計原則があります。
今回は、このSOLID原則のうち、インターフェース分離の原則(Interface Separation Principle, ISP)についてRubyのサンプルコードを用いて解説していきます。
目次 / Index
SOLIDとは
SOLIDとは、5つの原則の頭文字を取った略語です。
- Single Responsibility Principle(SRP): 単一責任原則
- Open Closed Principle(OCP): オープン・クローズドの原則
- Liskov Substitution Principle(LSP): リスコフの置換原則
- Interface Separation Principle(ISP): インターフェース分離の原則
- Dependency Inversion Principle(DIP): 依存性逆転の原則
インターフェース分離の原則 (Interface Separation Principle, ISP)とは
インターフェース分離の原則は、インターフェースを利用する具像クラスが使用しないメソッドに依存することを避けるため、インターフェースを細分化するという原則です。
巨大で複雑なインターフェースの代わりに、ニーズに特化した小さなインターフェースを作成します。
いわゆるインターフェース版の単一責任原則ですね。
主に以下のメリットがあると思います。
- インターフェースを指定している呼び出す側から、無関係なメソッドが見えなくなるため使い方がシンプルになる。
- ニーズに特化し小さくすることで、呼び出されるメソッドを限定することができるため問題分析しやすくなる。
- 別の具像クラスに変更するとき、小さくしたインターフェースのメソッドだけを満たすだけで良く、変更が容易になる。
以降、解説していきます。
インターフェース分離の原則に違反しているコード
正直に言いますと、Rubyでは正しくサンプルコードを書くことが出来ません。
なぜなら、Rubyは言語的にダックタイピングの思想を用いており、インターフェースという仕組みがないためです。
JavaやTypeScriptであれば、具象クラスを作成する際、インターフェースにより不要なメソッドの作成を強制されるので、わかりやすいサンプルコードを書くことができるのですが、前述の理由により、Rubyだと難しくなります。
少し強引ですが、抽象クラスを用いて解説してみます。
以下のようなクラスがあったとします。
class Worker
def work
raise NotImplementedError, 'Subclasses must implement work method'
end
def eat
raise NotImplementedError, 'Subclasses must implement eat method'
end
def sleep
raise NotImplementedError, 'Subclasses must implement sleep method'
end
end
class Employee < Worker
def work
# ...
end
def eat
# ...
end
def sleep
# ...
end
end
class Robot < Worker
def work
# ...
end
def eat
raise NotImplementedError, 'Robots do not eat'
end
def sleep
raise NotImplementedError, 'Robots do not sleep'
end
end
この例では、Worker
抽象クラスがwork、eat、sleep
メソッドを定義していますが、Robot
クラスはeat
とsleep
メソッドを使用しません。これはインターフェース分離の原則に違反しています。
インターフェース分離の原則に則ったコード
以下のようにすることで改善出来ます。
class Worker
def work
raise NotImplementedError, 'Subclasses must implement work method'
end
end
module LivingBeing
def eat
raise NotImplementedError, 'Subclasses must implement eat method'
end
def sleep
raise NotImplementedError, 'Subclasses must implement sleep method'
end
end
class Employee < Worker
include LivingBeing
def work
# ...
end
def eat
# ...
end
def sleep
# ...
end
end
class Robot < Worker
def work
# ...
end
end
この例では、Robot
クラスはWorker
抽象クラスのみを継承し、不要なメソッドに依存しません。これにより、インターフェース分離の原則に準拠したコードになります。
これはあくまでもRubyで強引に解説しようとしたコードであり、現実的に使用するかというとそうではありません。(基本的にRubyではダックタイピングを用い、インターフェースをコードに落とし込むことはしないため。)
最後に
今回の原則で見えてきたことは、SOLID原則やデザインパターンなど、世には様々なプログラミングに関する原則がありますが、これら全てに従うのが正しいのではなく、言語特性やプロダクト特性などによって使い分けをしていく必要があるということです。
そのためにもそれぞれの原則を正しく理解し、将来的に負債とならないか?を突き詰めて適用していく必要があります。
こういった分野は、経験がものを言うと思いますので、日々、betterな設計がないか?を模索していくことが大事だと思います。