【はじめてのJava】抽象クラスを使う理由【クラスの継承編】
はじめてのJava
このシリーズでは、初めてJavaやプログラミングを勉強する方向けに、Javaによるプログラミングの基礎を説明していきます。
目標レベルは、Javaの資格試験の一つである「Oracle Certified Java Programmer, Silver」(通称Java Silver)に合格できる程度の知識の習得です。
はじめてJavaやプログラムに触れる方にもできるだけわかりやすい解説を心がけていきます。
クラスの継承編
クラスの継承編では、Javaを扱う上で重要な「クラスの継承」について扱っていきます。
前回は、クラスの抽象化を説明してきました。
今回は抽象クラスを定義する理由を改めて考えてみます。なお、この内容はJava Silverよりも少し高度な内容です。
目次
クラスの設計
プログラムを作るときに、いきなりソースコードの作成を始めることはまずありません。通常はまずプログラムの全体像やクラスの設計図を考えます。
今回は抽象クラスを定義する理由を考えてみます。
抽象クラスを定義する理由
前回は「Cat」と「Dog」を基に「Animal」クラスを定義しました。その際に「Animal」を抽象クラスとして定義することで、正体不明の動物インスタンスが生成されないようにしました。
しかしわざわざ抽象クラスにしてまで、直接Animalをインスタンス化されないようにする必要はあるのでしょうか。
システム作成時を考える
では、少し視点を変えて、「システム作成時」の目線で考えてみましょう。
システムは、たくさんのクラスを組み合わせて作成していきます。10や20程度であれば、すべてのクラスを把握して作成することは可能かもしれません。しかし、50、100、…となってくると、すべてを把握するのは難しくなってきます。
また、ソースコードが1000行、2000行…と膨大な行数になることもあるでしょう。
このような状況で「Animal」をインスタンス化できるクラス(具象クラス)として定義してしまうと、システムのどこかで誤って「Animal」を直接インスタンス化してしまう個所が出てくるかもしれません。
そうなると、「正体不明の動物インスタンス」ができてしまいます。
これではバグの原因になってしまいます。そこで、「インスタンス化させたくないクラス」という意味合いで抽象クラスとして定義し、誤ってインスタンス化されることを設計段階で防ぎます。
そこまでして定義するべきか
そう考えると、「そこまでして抽象クラスとして定義するべきなのか」という考えもよりぎります。そこまでしないでも「Cat」と「Dog」をバラバラに定義しておけばいいではないか、と考えられます。
しかし、これでは利便性が下がります。どういうことでしょうか。
ポリモフィズムと組み合わせる
以前の記事で書いた通り、多態性(ポリモフィズム)を利用することで、「柔軟性が高いプログラム」を書くことができます。
例えば「Car」を継承した「PoliceCar」と「Ambulance」があったとします。
このような設計になっている場合、「Carの配列」「CarのCollection」として「PoliceCar」も「Ambulance」もまとめて扱えます。
これは、親クラスが抽象クラスだった時も同じです。
例えば今回のように「Cat」と「Dog」、そしてその親クラスである「Animal(抽象クラス)」があったとします。
このような場合でも実は「Animalの配列」や「AnimalのCollection」を定義し、その中で「Cat」や「Dog」をまとめて扱うことが可能です。
Animal自体はインスタンス化できませんが、このようにAnimalの配列/Collectionとしてまとめて扱えるので、プログラムの柔軟性が上がります。
まとめ
クラスの抽象化をした際に、親クラスを抽象クラスとして定義すると、システム作成時のバグ防止につながる。
親クラスが抽象クラスでも、配列やCollectionとポリモフィズムを組み合わせることででまとめて扱うことができる。
次回
次回もクラスの設計について考えてみます。
はじめてのJavaシリーズの目次はこちら
クラスの継承編はこちら