こんにちは、ハニ太郎(@82_taro)です♪
私たちは現実世界において無意識に多くのものを抽象的に捉え利用しています。
オブジェクト指向の目的が現実世界の再現である以上、プログラム内でも抽象的にものを捉える必要があるといえるでしょう。
今回の記事ではそんな抽象的で曖昧なクラスを正しく安全に便利に利用するための「抽象クラス」「インターフェース」について解説していきます。
ハニ太郎
はじめに
本記事では、継承の基礎が理解できていることを前提に話を進めていきます。
>【オブジェクト指向入門】継承とは?(基本編)わかりやすく解説
そのため、継承の知識に不安のある方は先に上記の記事を読んでおいてください。
なお、本記事では継承関係の図における上側の部分すなわち「曖昧なクラスたち(汎化型クラス)」の定義方法を学んでいきます。
これらを学ぶにあたって念頭において欲しいコツが1つございます。
それは”新しい立場で考える”という意識。
一体どういうことか?
一般的な継承を学んだあなたは、プログラムのためだけに必要なクラスを作って目的のプログラムを完成させる立場をこれまで取ってきたはずです。
そして、もし開発すべきクラスと類似した既存のクラスがあれば、継承を利用して子クラスを作ることにより効率よくクラスを開発できるのでした。
ここで既存のクラスに着目してみてください!
きっとこのクラスを事前に開発しておいてくれた開発者がどこかにいるはずです。
その開発者は「いつか誰かが、このクラスを継承して開発したら便利だろう」と未来に思いを馳せ、継承の材料となる既存のクラスを作ってくれたと考えられます。
今回学ぶ「抽象クラス・インターフェース」では、まさしくこの立場に立ってクラスを作るのです。
言い換えると、「抽象クラス」「インターフェース」とは、現場の人達に安全かつ便利に使ってもらえる親クラスを作るための道具といえます。
この意識を持っているか否かで後の抽象クラスとインターフェースの理解に雲泥の差がでます。
ここで立場をしっかりと理解しておきましょう。
2つの不都合と3つの心配事
「他の開発者が効率よく安心して利用できる継承の材料を作る立場」をとった際、2つの不都合と3つの心配事が想定されます。
ここで「メソッドが確定できないのであれば中身をからにしておけばいいのでは?」と思ったかもしれませんが、そうなると2つの心配事が出てきます。
「オーバライド」とは、同名のメソッドを子クラスで書き換えることです。
オーバライドをし忘れると、メソッドは呼び出せるが何もおきないという不具合を抱えたクラスになってしまいます。
エラーは起きないけど想定外の変な動きをするというタチの悪い不具合です。
これに対して「ソースコードにコメントを残しておけばいいのでは?」とお考えになったかもしれませんが、そのコメントを見逃したり無視したりする可能性は残ります。
メソッドの中身を空にしておくと、呼ばれても何もしないメソッドと区別がつかないのです。
今回の場合は「何もしない」のではなく、「何をするか未定で記述できない」だけなのでこれは問題となります。
のちの開発者が何もしないメソッドだと勘違いしてしまう恐れがあるからです。
クラスには以下2つの利用方法があります。
- newによる利用:インスタンスを生成するためにそのクラスを利用。
- 継承による利用:別クラスを開発する際にあるクラスを継承元として利用。
このクラスには自由に選べる2つの利用法があるという利点が、ある心配事の原因となり得ます。
未来の開発者が継承のためのクラスを間違えてnewして利用してしまうかもしれないのです。
そもそも詳細未定な部分が残っているクラスはインスタンス化されるべきではありません。
未完成品の車が世に出回っていたら怖いですよね?
抽象クラス
前章では継承の材料となるクラスを作ろうとすると問題になる2つの不都合と3つの心配事について述べました。
この問題点を解決するために用意されている仕組みが本章と次章で解説する「抽象クラス」と「インターフェース」。
まず始めに本章で「抽象クラス」について解説いきたいと思います。
ハニ太郎
第二の心配事は、空のメソッドを作っておくと”現時点で処理内容を確定できないメソッド”と”何もしないメソッド”の区別がつかないというものでした。
実は各言語に詳細未定メソッド(抽象メソッド)を記述する専用の構文が用意されています。
具体的な構文は「現在あなたが学んでいる言語|抽象メソッド|構文」で検索してみてください。
この記法のおかげで空メソッドは”何もしないメソッド”、抽象メソッドは”何をするか現時点で確定できないメソッド”と区別できるようになるため第二の心配事は解決です。
ハニ太郎
第三の心配事は、未完成部分を含む継承のためのクラスを誤まってnewされる可能性があるというものでした。
基本的に「未完成部分(抽象メソッド)を1つでも含むクラス」は、クラス宣言をする際に専用の構文を用いることになっております。
このようなクラスを特に抽象クラスと呼びます。
具体的な構文は「現在あなたが学んでいる言語|抽象クラス|構文」で検索してみてください。
抽象クラスはnewによるインスタンス化が禁止されています。
そのため、継承専用のクラスは抽象クラスとして宣言すれば、間違ってnewされることはないので第三の問題も解決です。
ハニ太郎
第一の心配事は、未来の開発者が詳細未定メソッドをオーバーライドし忘れる可能性があるというものでした。
この心配事は、実はすでに解決しています。
継承の基本をおさらいしましょう。
クラスを継承することによって親クラスのすべてのメンバ(フィールド・メソッド)を子クラスが受け継ぐのでしたね?
そして今回の場合だと継承したメンバの中に抽象メソッドも含まれているはずです。
つまり、子クラス自体のソースコード内に抽象メソッドが存在しなくとも、親クラス(抽象クラス)から抽象メソッドを継承して持っていると言えます。
そして抽象メソッドはオーバーライドし、中身を確定するまでは利用できませんので第一の心配事もこれで解決です。
ちなみに未定メソッドの内容を確定させることを「実装」すると表現することもあります。
インターフェース
この章では「インターフェース」について解説していきたいと思います。
インターフェースとは、以下の2つ条件を満たした抽象クラスを指します。
- 全てのメソッドが抽象メソッド
- 基本的にフィールドを1つも持たない
言うなれば抽象クラスの中でも特に抽象的なスーパー抽象クラスのようなものです。
そして上記の条件を満たした抽象クラスすなわち「インターフェース」は、特別扱いすることができるのです。
インターフェースによる効果(メリット)は大きく分けて以下の3つ。
- 複数の子クラスたちに共通のメソッド群を実装するよう強制できる。
- あるクラスがインターフェースを実装していれば、少なくともそのインタフェースが定めたメソッドは持っていることが保証される。
- 特別に多重継承が許される。
上記のようなメリットがあるため「インターフェース」という特別な概念が存在するのです。
使いこなせるようになればとても便利な機能ではありますが、まずは抽象クラスを理解することの方が重要ですので、難しいと感じた場合は焦らず先にそちらの理解に努めるようにしてください。
おわりに
ハニ太郎
少し内容が難しく一度で理解しきれなかったかもしれませんが、何事も継続が大切ですのでめげずに頑張ってください(^^)
あなたが継承を使いこなしオブジェクト指向型プログラムを作れるようになれるよう応援しております♪
また、継承について理解できたら次に多態性について学ぶのがおすすめです。
>【オブジェクト指向入門】多態性(ポリモーフィズム)とは?わかりやすく解説
多態性については上記の記事で解説しているので参考にしてみてください。
コメントを残す