オブジェクト指向プログラミング(OOP)において重要な役割を果たす継承という機能ですが設計が杜撰だと仕様変更の際などに致命的なバグにつながってしまいます。
まずオブジェクト指向とは何なのかという話ですが、簡単に言うとclassという設計図を作ってそれをインスタンス化することでそれに関するプロパティやメソッドをまとめてしまおうというものです。
例としては、Dog(いぬ)というクラスを作ります。犬はご飯を食べる、水を飲む、よく吠えるなどの特徴を持っていますよね。それをコードにしてみたのが以下です。
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
// Your code here!
Dog dog = new Dog();
dog.bark();
}
}
class Dog {
void bark() {
System.out.println("Bow!");
}
void eat() {
System.out.println("Delicious!");
}
void drinkWater() {
System.out.println("GokuGoku");
}
}
class DogとなっているところがDogクラスの宣言部にあたります。そして、Mainクラス内のmain関数内がDogクラスのインスタンス生成部分になります。newで犬のインスタンスを生成して変数名.関数名の形で使えるので便利ですし、通常ファイルを分けるのでファイルの見通しもよくなり保守性がぐんと上がります。クラスの説明はこんな感じで終わりにして継承について説明します。
継承とはそのままなんですが親となるクラスのものをそのまま受け継げるというものです。上記のDogクラスでは動物ならご飯を食べるのも水を飲むのも共通事項ですよね。そんな時はAnimalというクラスを作って動物なら共通するというようなものをまとめておきます。そしてそれをDogクラスに継承させたら元のDogクラスと同じになるし、Catクラスを作るとなったときにAnimalクラスを継承させれば食べる、飲むといった行動を実装する必要もなくなります。コードは以下になります。
class Dog extends Animal {
void bark() {
System.out.println("Bow!");
}
}
class Cat extends Animal {
void highJump() {
System.out.println("Jump!!");
}
}
class Animal {
void eat() {
System.out.println("Delicious!");
}
void drinkWater() {
System.out.println("GokuGoku");
}
}
extendsで継承ができます。実際はクラスごとにファイルを分けたりするので元になるクラスを継承するだけでかなり一つ一つのファイルの見通しが良くなったのではと思います。
さて、長々とクラスと継承について説明しましたがここまでは前置きです。本題は冒頭で触れたクラスの杜撰な設計というところです。今回例示したような簡単なものだとバグにつながるようなことはあまりないかと思いますが、決済システム等の大規模なものだと取り返しのつかないバグにつながりかねません。特にやっつけ的に機能を追加していった場合以下の動画のようなことになる可能性が高いです。
https://twitter.com/minodriven/status/1353251239237095430
こんなことになったら泣きながら対応する羽目になるので設計には気を付けて書きましょうという話でした。
今回書いた言語はJavaです。