本記事は、掲載元で31K「いいね」を獲得したUgonna Thelma氏による「The S.O.L.I.D Principles in Pictures」(2020年5月18日公開)の和訳を、著者の許可を得て掲載しているものです。
#イラストで理解するSOLID原則
本記事に掲載されているイラストは、すべて原著者Ugonna Thelmaによるものです。
##はじめに
オブジェクト指向プログラミングに精通している方なら、SOLID原則について聞いたことがあるでしょう。
この5つのソフトウェア開発原則は、ソフトウェア構築時に従うべきガイドラインで、ソフトウェアの拡張性や保守性を高めるためのものです。これは、ソフトウェアエンジニアのRobert C. Martinが提唱したものです。
SOLIDに関する素晴らしい記事はネット上に数多くありますが、イラスト付きの例は滅多に見ません。そのため、私のような視覚的学習者には、飽きずに学習するのが少し難しくなります。
そのため、この記事の主な目的は、イラストを使用してこの原則をよりよく理解し、各原則の目的を明らかにすることです。
この原則のいくつかは、似ているように見えるかもしれませんが、目的が同じわけではありません。たとえ似ていても、一方の原則を満たしながら、もう一方の原則を破ることもあるのです。
この記事では、分かりやすくするために「クラス」という言葉を使用していますが、関数、メソッド、モジュールにも当てはまりますので、ご注意ください。
更新情報
この記事の「オープン・クローズドの原則」が「単一責任の原則」に違反している、というコメントがいくつかありました。この記事の目的は、それぞれの原則を独立して説明することです。また、責任(または役割)と動作は異なります。「単一責任の原則」では "I am a Painter"、「オープン・クローズドの原則」では "I can Paint" としています。
この点に注意することが重要です。1つの責任(役割)を果たすために、複数の動作を実行できるからです。クラスには1つの責任(単一責任の原則)が必要ですが、その責任を果たす機能は拡張可能(オープン・クローズドの原則)である必要があります。
さあ、始めましょう!
#SOLID原則
##S (Single Responsibility) 単一責任の原則
###クラスは、単一の責任を持つべきだ。
クラスに多くの責任があると、バグが発生する可能性が高くなります。なぜなら、その責任の1つに変更を加えると、知らないうちに他の責任に影響を与える可能性があるからです。
###目的
この原則は、変更の結果としてバグが発生しても、他の無関係な動作に影響を与えないように、動作を分離することを目的としています。
##O (Open-Closed) オープン・クローズドの原則
###クラスは、拡張にはオープンで、変更にはクローズドであるべきだ。
クラスの現在の動作を変更すると、そのクラスを使用するすべてのシステムに影響を与えます。
クラスでより多くの関数を実行したい時、理想的な方法は、既存の関数に追加することであり、変更しないことです。
###目的
この原則は、クラスの既存の動作を変更することなく、クラスの動作を拡張することを目的としています。これは、そのクラスが使用されている場所でバグが発生するのを避けるためです。
##L (Liskov Substitution) リスコフの置換原則
###SがTのサブタイプである場合、プログラム内のT型のオブジェクトをS型のオブジェクトに置き換えても、そのプログラムの特性は何も変わらない。
子クラスが親クラスと同じ動作を実行できない場合、バグになる可能性があります。
クラスから別のクラスを作ると、クラスが親になり、新しいクラスが子になります。子クラスは、親クラスができることをすべてできる必要があります。このプロセスを継承と呼びます。
子クラスは、親クラスと同じリクエストを処理し、同じ結果か、同様の結果を提供できなければなりません。
このイラストでは、親クラスがコーヒーを提供しています(コーヒーの種類は問いません)。子クラスがカプチーノを提供することは、カプチーノがコーヒーの一種なので許容されますが、水を提供することは許容されません。
子クラスがこれらの要件を満たさない場合、子クラスが大きく変更され、この原則に違反することになったということです。
###目的
この原則は、親クラスやその子クラスがエラーなしで同じ方法で使用できるように、一貫性を保つことを目的としています。
##I (Interface Segregation) インターフェイス分離の原則
###クライアントが使用しないメソッドへの依存を、強制すべきではない。
クラスに使用しない動作を実行させようとするのは、無駄が多く、クラスにその動作を実行する機能がない場合、予期しないバグが発生する可能性があります。
クラスは、その役割を果たすために必要な動作のみを実行する必要があります。それ以外の動作は完全に削除するか、将来的に他のクラスで使用する可能性がある場合は別の場所に移動すべきです。
###目的
この原則は、動作のセットをより小さく分割して、クラスが必要なもののみを実行することを目的としています。
##D (Dependency Inversion) 依存性逆転の原則
###・上位モジュールは、下位モジュールに依存してはならない。どちらも抽象化に依存すべきだ。
###・抽象化は詳細に依存してはならない。詳細が抽象化に依存すべきだ。
まず、ここで使用されている用語をより簡単に定義します。
上位モジュール(またはクラス):ツールを使って動作を実行するクラス
下位モジュール(またはクラス):動作を実行するために必要なツール
抽象化:2つのクラスをつなぐインターフェイス
詳細:ツールの動作方法
この原則では、クラスは動作を実行するために使用するツールと融合すべきではありません。むしろ、ツールがクラスに接続できるようにするインターフェイスと融合すべきです。
また、クラスもインターフェイスも、ツールの動作方法を知るべきではありません。ただし、ツールはインターフェイスの仕様を満たす必要があります。
###目的
この原則は、インターフェイスを導入することにより、上位レベルのクラスが下位レベルのクラスに依存するのを減らすことを目的としています。
##おわりに
5つの原則について説明し、その目的を明らかにしてきました。この原則は、問題をほぼ起こさずに、コードの調整、拡張、テストを容易にするためのものです。
お読みいただきありがとうございます。あなたがこのトピックへの理解を深め、私がこの記事を書いた時のように、あなたもこの記事を楽しんでくれたら嬉しいです。
ご質問やご意見がありましたら、コメントをお寄せください。
##翻訳協力
この記事は以下の方々のご協力により公開する事ができました。改めて感謝致します。
Original Author: Ugonna Thelma
Original Article: The S.O.L.I.D Principles in Pictures
Thank you for letting us share your knowledge!
選定担当: @gracen
翻訳担当: @gracen
監査担当: -
公開担当: @gracen
##ご意見・ご感想をお待ちしております
今回の記事はいかがでしたか?
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。
頂いたお声は、今後の記事の質向上に役立たせて頂きますので、お気軽に
コメント欄にてご投稿ください。Twitterでもご意見を受け付けております。
皆様のメッセージをお待ちしております。