単にプログラミング言語の文法を知っているだけでは優れたプログラムは書けない。どうすればより良いコードが書けるのかを解説する。
良い設計の指針としてSOLID原則があります。これは5つの原則の頭文字を組み合わせたもので、基本的には責務をどう分離・配置すれば良いのか、あるいは責務を分離する機能の設計指針を示すものです。以降で説明しましょう。
Single-responsibility principle(SOLIDのS)
日本語では単一責務の原則とも呼ばれます。あるいは頭文字をとって、SRPと呼ぶこともあります。
これはコンポーネント(関数やクラス)が保持する責務は1つであるべきだという原則です。先ほども説明しましたが、責務が複数あるとそれだけ変更される可能性が高くなりますし、安全に変更できる可能性が低くなってしまうからです。
ただ実際には、状況によって責務が複数混在していることを許容する場合もあります。複数混在している責務にほぼ変更が入らないことがわかっている(あるいは確信している)なら、問題にならないかもしれません。
Open-closed principle(SOLIDのO)
日本語では開放閉鎖の原則と呼ばれます。あるいは頭文字をとってOCPと呼ぶこともあります。
これは、機能追加について開いていて、修正に閉じているべきだという原則です。と言っても、何のこっちゃという感じですが、つまりは、機能追加するときに、既存コードを修正しなくて良いように設計しようという原則です。
では、そんなことが可能なのでしょうか? 実はすでにこの原則に従った例を示しています。継承を使って、商品種別を表現したコードがそれです。新たにbook種別が出てきても、Itemクラスを継承したBookクラスを定義するだけで機能拡張ができていました。このような拡張が可能なように設計しましょうというのが、この原則の言わんとするところです。
ただし、この原則には批判も出ています。というのも、完全にこの原則に従える拡張ばかりではなく、多くの場合、既存コードの修正というのは少なからず発生してしまうからです。また、やや過剰な原則だという批判もあります。
とはいえ、この原則の意図する「機能拡張時に既存コードを修正しない方が良い」というのは、基本的には一考に値する指摘だとは思います。
Liskov substitution principle(SOLIDのL)
日本語ではリスコフの置換原則と呼ばれます。ちなみにリスコフというのは、米国のコンピュータ科学者の名前です。
これは継承に関する原則で、親クラスのインスタンスが適用されるコードに対して、子クラスのインスタンスで置き換えても、問題なく動くべきだという原則です。もっと簡単に言うと、親クラスの振る舞いを子クラスが勝手に壊してはいけないという原則です。
具体例で考えましょう。例えば、あるネット販売のシステムを組んでいるとして、そのシステムにはお店のスタッフ(Staffクラス)と、お客さん(Customerクラス)という2種類の登場人物が現れます。
スタッフとお客さんはシステムにログインでき、商品を閲覧・購入できます。また、スタッフは商品を削除したりと、お客さんにはできないような行動ができます。
では、スタッフとお客さんに継承関係を付ける場合、どのようにすればいいでしょうか?
なんだか、スタッフの方が特別な存在なので、スタッフの方が親クラスでしょうか?
答えを言ってしまうと、お客さん(Customerクラス)が親クラスになります。この理由を与えるものがリスコフの置換原則になります。
まず、仕様としてお客さんができることは、スタッフもできます。ということは、お客さんインスタンスが現れるところを、スタッフインスタンスに変更しても問題なく動くはずです。例えば以下のようなコードです。
お客さんがログインして、商品を買った後にメールを送信するという関数になりますが、この引数customerがStaffクラスのインスタンスでも問題なく動くのであれば、スタッフ(Staffクラス)はお客さん(Customerクラス)を親として継承して良いでしょう。
逆にスタッフしかできない処理、商品の削除処理を考えてみましょう。
スタッフがログインして、商品を削除しています。ここでポイントになるのが、この変数staffにお客さん(Customerクラス)インスタンスを適用して良いかどうかです。当然、お客さんなので商品を削除できず、この関数の変数staffにお客さんインスタンスを適用できません。ということは仮にスタッフ(Staffクラス)が親クラスで、お客さん(Customerクラス)が子クラスとしてしまうと、リスコフの置換原則を満たさないことになり、そのような継承は良くないことがわかります。
これはis-a関係の説明にもなります。親クラスができることは子クラスもできるべきだというのは、子クラスは親クラスの一種だと捉えることができます。今の例で言えば、スタッフはお客さんの一種(Staff is-a Customer)ならば、継承しても良いということになります(逆に「お客さんはスタッフの一種」とはならないので、スタッフを親クラスにすることは良くありません)。