この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:atom
更新日時:2026-06-11 07:10:02

タイトル: ポリモーフィズム(多様性)の具体例
SEOタイトル: ポリモーフィズム (多態性) の具体例 - 動物クラス・図形・Strategy パターン・実務での効果

この記事の要点
  • ポリモーフィズム: 同じメソッド呼び出しでも、実体クラスに応じて挙動が変わる仕組み
  • 代表例: Animal 型の参照で Dog.bark()Cat.bark() を呼ぶと、それぞれの実装が動く
  • instanceof での分岐が不要になる → 拡張に強い (OCP: 開放閉鎖原則)
  • List を for で回すだけで各動物が自分の動きをする
  • 実務での効果: Strategy パターン / Template Method / 戦略の切り替えがコード変更なしで可能

ポリモーフィズムとは

「多態性」「多様性」と訳される OOP の中心概念。同じ操作 (メソッド呼び出し) でも、対象の型によって異なる挙動になる性質。Java / PHP / Python など多くの言語で「オーバーライド」+「上位型での参照」で実現する。

古典例: 動物クラス

// 親クラス (抽象)
public abstract class Animal {
    private String name;
    public Animal(String name) { this.name = name; }
    public String getName() { return name; }

    public abstract String bark();   // サブクラスでオーバーライド
}

// 犬
public class Dog extends Animal {
    public Dog(String name) { super(name); }
    @Override
    public String bark() { return "ワン!"; }
}

// 猫
public class Cat extends Animal {
    public Cat(String name) { super(name); }
    @Override
    public String bark() { return "ニャー"; }
}

// 牛
public class Cow extends Animal {
    public Cow(String name) { super(name); }
    @Override
    public String bark() { return "モー"; }
}

ポリモーフィズムが効くシーン

// ✅ Animal 型のリストに犬・猫・牛を混在させる
List<Animal> animals = new ArrayList<>();
animals.add(new Dog("ポチ"));
animals.add(new Cat("タマ"));
animals.add(new Cow("モモ"));

// 同じループで各々の鳴き声が出る
for (Animal a : animals) {
    System.out.println(a.getName() + ": " + a.bark());
}
// → ポチ: ワン!
//   タマ: ニャー
//   モモ: モー

// 新しい動物 (Sheep) を追加してもループは無修正!
animals.add(new Sheep("ふわ"));   // → ふわ: メェー

ポリモーフィズムが無い世界 (反面教師)

// ❌ ポリモーフィズム未使用: instanceof で分岐
public String bark(Object animal) {
    if (animal instanceof Dog) {
        return "ワン!";
    } else if (animal instanceof Cat) {
        return "ニャー";
    } else if (animal instanceof Cow) {
        return "モー";
    }
    // 動物が増えるたびに if が増える → OCP 違反
    return "...";
}

// ✅ ポリモーフィズム使用: 呼ぶだけ
public String bark(Animal animal) {
    return animal.bark();   // 1 行で済む
}

図形クラスでの例

public abstract class Shape {
    public abstract double area();
    public abstract double perimeter();
}

public class Circle extends Shape {
    private double radius;
    public Circle(double r) { this.radius = r; }
    public double area() { return Math.PI * radius * radius; }
    public double perimeter() { return 2 * Math.PI * radius; }
}

public class Rectangle extends Shape {
    private double width, height;
    public Rectangle(double w, double h) { this.width = w; this.height = h; }
    public double area() { return width * height; }
    public double perimeter() { return 2 * (width + height); }
}

public class Triangle extends Shape {
    private double a, b, c;
    public Triangle(double a, double b, double c) { this.a=a; this.b=b; this.c=c; }
    public double area() {
        double s = (a + b + c) / 2.0;
        return Math.sqrt(s * (s-a) * (s-b) * (s-c));
    }
    public double perimeter() { return a + b + c; }
}

// 利用
List<Shape> shapes = List.of(
    new Circle(5),
    new Rectangle(3, 4),
    new Triangle(3, 4, 5)
);

double totalArea = shapes.stream()
    .mapToDouble(Shape::area)
    .sum();

ファクトリパターンとの組み合わせ

// 文字列から動物を生成
public class AnimalFactory {
    public static Animal create(String kind, String name) {
        return switch (kind) {
            case "dog" -> new Dog(name);
            case "cat" -> new Cat(name);
            case "cow" -> new Cow(name);
            default    -> throw new IllegalArgumentException(kind);
        };
    }
}

// 利用
String[] kinds = { "dog", "cat", "cow" };
List<Animal> animals = Arrays.stream(kinds)
    .map(k -> AnimalFactory.create(k, "?"))
    .toList();

animals.forEach(a -> System.out.println(a.bark()));

Strategy パターン (戦略パターン)

「アルゴリズムを差し替え可能にする」古典的なポリモーフィズム応用:

// 並び替え戦略
public interface SortStrategy<T> {
    List<T> sort(List<T> list);
}

public class BubbleSort<T extends Comparable<T>> implements SortStrategy<T> {
    public List<T> sort(List<T> list) { /* O(n^2) */ return ...; }
}
public class QuickSort<T extends Comparable<T>> implements SortStrategy<T> {
    public List<T> sort(List<T> list) { /* O(n log n) */ return ...; }
}
public class MergeSort<T extends Comparable<T>> implements SortStrategy<T> {
    public List<T> sort(List<T> list) { /* 安定 */ return ...; }
}

// 利用側はインターフェースだけ知っている
public class Sorter<T> {
    private SortStrategy<T> strategy;
    public Sorter(SortStrategy<T> s) { this.strategy = s; }
    public List<T> doSort(List<T> list) { return strategy.sort(list); }
}

new Sorter<>(new QuickSort<>()).doSort(myList);
new Sorter<>(new MergeSort<>()).doSort(myList);

Template Method パターン

共通の流れだけ親クラスに書き、差分はサブクラスで上書き:

public abstract class ReportGenerator {
    // テンプレートメソッド (確定アルゴリズム)
    public final String generate() {
        StringBuilder sb = new StringBuilder();
        sb.append(header());
        sb.append(body());      // ← サブクラスで実装
        sb.append(footer());
        return sb.toString();
    }
    protected String header() { return "===== レポート =====\n"; }
    protected String footer() { return "==== ここまで ====\n"; }
    protected abstract String body();
}

public class SalesReport extends ReportGenerator {
    protected String body() { return "売上: 1,000,000円"; }
}
public class StockReport extends ReportGenerator {
    protected String body() { return "在庫: 250 個"; }
}

new SalesReport().generate();
new StockReport().generate();

実務での効果

シーンポリモーフィズム適用例
支払い方法カード / 銀行 / コンビニ → PaymentMethod#pay()
通知Email / Slack / Push → Notifier#send()
エクスポートCSV / Excel / PDF → Exporter#export()
認証Local / OAuth / SAML → Authenticator#authenticate()
キャッシュRedis / Memcached / File → Cache#get()

PHP での例

<?php
interface Notifier {
    public function send(string $to, string $message): void;
}

class EmailNotifier implements Notifier {
    public function send(string $to, string $message): void {
        mail($to, '通知', $message);
    }
}
class SlackNotifier implements Notifier {
    public function send(string $to, string $message): void {
        // POST to Slack Webhook
    }
}
class LineNotifier implements Notifier {
    public function send(string $to, string $message): void {
        // POST to LINE Notify
    }
}

// 利用側は具体クラスを知らない
function notifyAll(array $notifiers, string $to, string $msg): void {
    foreach ($notifiers as $n) {
        $n->send($to, $msg);
    }
}

notifyAll([
    new EmailNotifier(),
    new SlackNotifier(),
    new LineNotifier(),
], 'user@example.com', '緊急通知');

FAQ

Q: オーバーロード (引数違いの同名メソッド) もポリモーフィズム?
A: 厳密にはアドホック多相と呼ばれ別物。OOP で「ポリモーフィズム」と言えば通常はオーバーライドによるサブタイプ多相を指す。

Q: ポリモーフィズムを使うとパフォーマンスが落ちる?
A: 仮想メソッド呼び出しのコストは現代の JIT で誤差レベル。可読性・保守性のメリットが圧倒的に勝る。

Q: 関数型言語のポリモーフィズム?
A: パラメトリック多相 (ジェネリクス) + 型クラス (Haskell) / 高階関数で実現。OOP のサブタイプ多相とは別系統。