ポリモーフィズムを活かす
種類が 1 つ増えるたびに、if を 1 本足している
通知をまとめて送る処理を、種類ごとの分岐で書いたとします。
Java
for (Object n : notifications) {
if (n instanceof MailNotification m) {
m.sendMail();
} else if (n instanceof PushNotification p) {
p.sendPush();
}
}SMS 通知を足したくなったら、この if に 1 本足します。同じような分岐が別の場所にもあれば、そこも全部です。種類が増えるたびに直すのは、通知クラスではなく 呼ぶ側 なのが厄介なところです。
親の型で受けて、同じ 1 行で呼ぶ
親に共通のメソッド名を決めておき、子がそれぞれ中身を書きます。呼ぶ側は親の型でしか受け取りません。
Java
abstract class Notification {
public abstract String send();
}
class MailNotification extends Notification {
@Override
public String send() {
return "メールを送信しました";
}
}
class PushNotification extends Notification {
@Override
public String send() {
return "プッシュを送信しました";
}
}Notification n = new MailNotification(); のように、左を親の型・右を子の型にして代入できます。これを アップキャスト と呼び、(Notification) のような書き足しは要りません。
そのうえで n.send() と呼ぶと、変数の型は Notification なのに、実際に動くのは MailNotification の send() です。Java が実行時にインスタンスの本当のクラスを見て呼び先を決めるからで、これが ポリモーフィズム の正体です。
まとめて入れて、1 回のループで回す
要素の型を親にすれば、種類の違う子をひとつのリストに混ぜられます。
Java
List<Notification> list = List.of(new MailNotification(), new PushNotification());
for (Notification n : list) {
System.out.println(n.send());
}ループの中に分岐は 1 つもありません。SMS 通知のクラスを足しても、直すのはリストに入れる場所だけで、このループは触らずに済みます。冒頭の if の連なりが消えた、ということです。
呼ぶ側で
instanceofを並べたくなったら、それは「親に置くべきメソッドがまだ無い」という合図です。分岐の中身に共通の名前を付けられないか、先に考えてみてください。
やってみよう
totalArea(int circleR, int squareS) を完成させてください。
Shapeをabstract classとして宣言し、public abstract int area();を持たせるCircle extends Shapeのarea()はr * r、Square extends Shapeのarea()はs * sを返す。半径と一辺はコンストラクタで受け取るtotalAreaの中でList<Shape>を作り、CircleとSquareを 1 つずつ入れるfor-eachで取り出してarea()を足し合わせ、合計をintで返す
手順 4 のループの中で instanceof を書く必要はありません。Shape として取り出して area() を呼ぶだけで、円なら円の、正方形なら正方形の計算が動きます。List を使うので java.util.List の import を忘れないでください。
要件
Shapeをabstract classとして宣言し、抽象メソッドpublic abstract int area();を持たせることCircle extends Shapeでr * rを返すarea()、Square extends Shapeでs * sを返すarea()を実装することSolution.totalArea(int circleR, int squareS)の中でList<Shape>にnew Circle(circleR)とnew Square(squareS)を入れ、for-eachでarea()を合計してintで返すこと
入出力例
totalArea(2, 3) → 13
totalArea(5, 1) → 26
totalArea(1, 0) → 1