目次
「継承」とは「プログラムコードを再利用する方法」の一つ
こんにちは。技術チームの岩谷です。前回からオブジェクト指向プログラミング(OOP)をおさらいする連載をはじめました。今回は第二回としてOOP言語が持つ機能の一つである「継承」について説明します。継承機能を活用することによって既存のプログラムソースコードを効率的に再利用することが可能です。
「継承される側」には「共通部分」を、「継承する側」には「差分」を
継承機能を利用することによってコードが再利用される例として、今回は以下のサンプルコードを用意しました。クラスが3つ掲載されています。このサンプルによってコードを再利用する方法についてご理解いただければと思います。
[サンプルコードの業務仕様]
営業社員一人の
- 社員ID
- 社員名
- 性別
- 今日は出勤している?していない?
- その営業社員が持っている顧客の数
という情報を画面に表示する。
[クラスの説明]
- クラス「Test」:OOPで作られたクラスを呼び出す(利用する)クラスです。
- クラス「ClassEigyoShain」:「営業社員」クラスです。OOPで作られたクラスです。下記cの「ClassShain」を継承して作られたクラスで、今回の継承機能を説明する上では「子クラス=サブクラス」となるクラスです。
- クラス「ClassShain」:「社員」クラスです。OOPで作られたクラスです。上記bの「ClassEigyoShain」の継承元となるクラスで、今回の継承機能を説明する上では「親クラス=スーパークラス」となるクラスです。
[継承の考え方]
今回の継承機能の説明においてもっとも注目していただきたいのは、上記b「営業社員クラス:ClassEigyoShain」です。このクラスは、上記c「社員クラス」を継承して(元にして)作成します。これは「現実的な事象として、営業社員という職業は、社員という職業を内包している」という考え方に基づいた設計になっています。
上記のプログラムが継承機能を用いる目的、それは「上記bの[営業社員クラス:ClassEigyoShain]のプログラムコード量を削減する」事にあります。「営業社員という職業が社員という職業を内包するのであれば、内包される部分、すなわち上記c「社員クラス」のコードは再利用したい」という考え方がここにはあります。
では、具体的なコードを見てみましょう。
まず注目していただきたいのは、上記aのクラス「Test」には上記c「社員クラス:ClassShain」に関する記述が1つもないことです。クラスTestが利用しているモノ(オブジェクト)はあくまで「営業社員」であり「社員」というモノ関係ないという事がわかります。
ここから継承機能の説明に入ります。「上記bのClassEigyoShain」の2行目を見てください。「Class ClassEigyoShain extends ClassShain」これが「営業社員クラスは社員クラスを継承しますよ」という意味を持ちます。
次にクラスTestの13行目を見てください。「社員ID=shainId」を画面に表示しようとしています。しかしこのshainIdはクラスClassEigyoShainの中に記述がありません。どこにあるのでしょうか?答えはクラスClassShainの5行目にあります。これがOOPにおける継承機能の代表的な利用方法の一つです。この5行目のコードが「継承によって再利用されたコード」です。継承機能によってクラスClassEigyoShainのコード量を少なくすることに成功しているのです。また、このshainIdを扱う業務仕様に変更が発生した場合においても、修正対象はこの5行目のコードに関連した部分のみを修正すればよいのでクラスClassEigyoShainは修正の必要がありません。コードの再利用によって共通化された機能がシステム全体のメンテナンス性向上に貢献しているのです。
そして最後にクラスTestの25行目を見てください。「その営業社員が持っている顧客の数」を画面に表示しようとしています。この部分はクラスClassEigyoShainが自身のソースコードの13行目にもっています。「その営業社員が持っている顧客の数」は「営業社員クラスという職業ならではのデータ」なので「社員クラス」がもっている必要がありません。いうなれば「営業社員」と「社員」の「差分」といえる部分です。「営業社員クラス=ClassEigyoShainはこの差分のみをプログラムコードとしてもっていればいい」これがOOPの継承機能の考え方のひとつです。
継承機能のプログラミングは簡単。でも継承機能の設計はむずかしい
ここまで継承機能の説明を簡単なサンプルをまじえて説明しました。プログラミングテクニックそのものは簡単である事をご理解いただけたと思います。しかしここで申し上げたいことがあります。それは「プログラミングと設計は別物である」ということです。継承機能そのものはプログラミングテクニックにすぎません。それを使ってどのように機能を実現していくかという設計がキモになります。
ここで誤解を承知で極端な一例を挙げます。ハンバーガー屋さんです。まず「ハンバーガー」と「チーズバーガー」を思い浮かべてください。私も過去にハンバーガー屋さんでバイトをしていましたが、チーズバーガーはハンバーグと下側のパンとの間にチーズを挟んだだけで、あとは同じでした。この場合「チーズバーガーはハンバーガーを継承して作成できる」と言えるでしょう。
クラス[ハンバーガー]
- 上側のパン
- からし
- ケチャップ
- レタス
- ピクルス
- ハンバーグ
- 下側のパン
クラス[チーズバーガー]←ハンバーガーを継承
- 上側のパン(←ハンバーガーを再利用)
- からし(←ハンバーガーを再利用)
- ケチャップ(←ハンバーガーを再利用)
- レタス(←ハンバーガーを再利用)
- ピクルス(←ハンバーガを再利用)
- ハンバーグ(←ハンバーガーを再利用)
- チーズ(←差分)
- 下側のパン(←ハンバーガーを再利用)
こんな継承関係が設計できます。再利用率が非常に高いです。良い設計だと思います。次に「てりやきバーガー」を思い浮かべてください。
クラス[てりやきバーガー]←ハンバーガーを継承
- 上側のパン(←ハンバーガーを再利用)
- マヨネーズ(←差分なので追加実装)
- レタス(←ハンバーガーを再利用)
- てりやきソース(←差分なので追加実装)
- ハンバーグ(←ハンバーガーを再利用)
- 下側のパン(←ハンバーガーを再利用)
これも再利用率がそこそこ高くて、継承設計としては妥当なのではないでしょうか。ここからが問題です。「ビッグ○ック」いってみましょう!
クラス[ビッグ○ック]←ハンバーガーを継承…していいの?
- 上側のパン(←専用パン=差分)
- ビッグ○ックソース(←専用ソース=差分)
- レタス(←ハンバーガーを再利用てきるかも)
- ハンバーグ(←ハンバーガーを再利用できるかも)
- 真ん中のパン(←専用パン=差分)
- ビッグ○ックソース(←専用ソース=差分)
- レタス(←差分=上のレタスをすでに再利用対象としているため)
- ハンバーグ(←差分=上のハンバーグをすでに再利用対象としているため)
- チーズ(←差分)
- 下側のパン(←専用パン=差分)
どうでしょう?再利用しているのはレタスとハンバーグだけです。いかんせんパンが再利用できないのがイタいですね?パッと見の感覚的には「ハンバーガー」→「チーズバーガー」→「ビッグ○ック」なのですが設計的にはおそらくビッグ○ックには継承機能を利用しないほうがよいのでしょう。
このように「現実の事象もしくは実際にシステムに求められる機能としての在り方」は「単純な継承関係」で表現するには複雑さや例外が多すぎるものです。これを「事象に対する深い観察眼」「高度な概念化」「継承機能を用いる?用いない?の判断」「用いる場合の対象設計」という「設計能力」で最善解を導くことが必要になるのです。
次回は「インターフェース」について
今回は連載の第二回としてOOPの持つ継承機能について説明させていただきました。次回は継承機能と並んでOOP言語が持つ特徴的な機能の一つである「インターフェース」について説明します。
追伸
私がアルバイトをしていたのはかなり昔でしかも○ックではないので上記の例は調理マニュアルとあっていないと思いますがごめんなさい。その中でも「ハンバーガーとてりやきバーガーはレタスの量が違うから再利用できないよね~?!」と思ったあなた!さすがです!!