はじめに
ポリモーフィズムについて調べると、動物を例に挙げてどうやってポリモーフィズムを実現させるかという説明をよく目にします。しかし、ポリモーフィズムもプログラミングを分かりやすくするためのtipsなのであくまで手段です。どのようにポリモーフィズムを満たすかも重要ですが、なぜポリモーフィズムを満たしたらプログラミングが分かりやすくなるのかがより重要だと思います。この記事では「なぜポリモーフィズムを満たしたらプログラミングが分かりやすくなるのか」について触れようと思います。
ポリモーフィズムとは
まずは目的を話す前に、ポリモーフィズムとはを簡単に説明します。ポリモーフィズムとは抽象クラスを使い、「抽象的な振る舞い」が状態に応じた「具体的な振る舞い」をすることです。
抽象的な振る舞いと具体的な振る舞いという単語を使いましたが、私の造語です。「振る舞い」という単語私の中で2種類あるので、明確にするために分けました。それぞれの定義は以下の通りです。
抽象的な振る舞い
抽象度が高い振る舞い。動物は「鳴く」、動物は「走る」など。プログラムで言うと抽象メソッド。どういう型の引数と取り、どういう型の返り値を返すなど。リスコフ置換の原則で言われる振る舞いはこっち。具体的な振る舞い
抽象度の低い振る舞い。犬は「ワンと鳴く」、チーターは「時速100㎞で走る」など。プログラミングで言うと具象メソッド。実際のロジックが記載される。ポリモーフィズムで言われる振る舞いはこっち。
ポリモーフィズムの目的
この記事の本題に入りたいと思います。私が思うにポリモーフィズムの目的は以下2点だと思います。それぞれ説明していきます。
・呼び出し側でif文やswitch文を無くす。
・システムの拡張を簡単にする。
呼び出し側でif文やswitch文を無くす
ポリモーフィズムとは抽象的な振る舞いが状態に応じて具体的な振る舞いをすることです、なので子クラスは親クラスと異なる抽象的な振る舞いをしてはいけません(メソッドを増やしたり、引数を広げたり戻り値を狭めたりする分には問題ない)。SOLIDの原則の一つであるリスコフ置換の原則を守る必要があります。
上記を満たすことで、呼び出し側は状態を意識せずに親クラスの抽象的な振る舞いに(親クラスの型)対してプログラムを行うことが出来ます。
状態を意識したプログラミングとは様々意見あると思いますが、ここではステータスや選択値を使いif文やswitch文で処理を分岐しているプログラミングとします。このようなプログラミングは単純にコードが肥大化し可読性が下がるのと、if文やswitch文が乱立して何をしたいプログラムなのかが判断つきにくくなったり、コードを読むときに状態を意識して読む必要があったり、誤った条件文を修正してしまうなどの恐れがあります。
親クラスの抽象的な振る舞いに対してプログラミングを行うことで、if文やswitch文をなくすと説明しましたが、呼び出し側で子クラスのインスタンスを作成するタイミングで結局if文、switch文必要になってしまうのではという疑問を持たれた方もいるかもしれません。この問題はFactoryパターンで回避したりします。
サンプルコードは気が向いたら作成して追記します。
以下の本の序盤の方で同じような説明がされていて、サンプルコードもあるのでここまでで興味持たれた方は読んでみてください。
システムの拡張を簡単にする。
ポリモーフィズムはリスコフ置換の原則を守る必要があると説明しました。これにより呼び出し側は親クラスの抽象的な振る舞いに対してプログラミングを行うことが出来ます。つまり呼び出し側はどの子クラスを利用しようが関係がないということになります。
決済を行うシステムを例に考えてみます。前提として既存の決済方法としてはクレジット決済とコンビニ決済があり、新しくQR決済が増えるとします。
ポリモーフィズムを利用していない場合は、if文やswitch文で決済方法ごとの分岐を行い支払い処理を行っているので、QR決済用に新しく分岐を用意する必要が出てきます。これは機能の拡張を行うのに既存のコードの修正をしているので、オープンクローズドの原則を守れていません。
一方でポリモーフィズムを利用している場合は、上述したように呼び出し側は親クラス(今回の例でいうと決済クラス)の抽象的な振る舞いに対してプログラミングを行っています。QR決済を増やす場合、決済クラスを継承したQR決済クラスを新しく実装するだけになります。これは機能の拡張を行うのに既存のコードの修正をしていないので、オープンクローズドの原則を守れています。
オープンクローズドの原則を守ると、機能を拡張する際、既存のコードの影響を考えなくて済むのと、単体テストが行いやすくなるため、機能の拡張が容易になります。
まとめ
ポリモーフィズムの行っていることは振る舞いの抽象化です、振る舞いを抽象化する必要がなければ、ポリモーフィズムを利用しなくていいです。普通に抽象データ型で対応しましょう。