本ページはプロモーションが含まれています

Java入門

Javaデザインパターン入門|過剰設計しない5選

CATEGORY
REV.
DRAWN BY
TOM
SHEETS
7枚
Design Pattern(過剰設計しない5選)

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

𝕏

Javaのデザインパターンとは、ソフトウェア設計の典型的な問題に対する再利用可能な解決策の型です。実務でよく使われるのはSingleton・Factory Method・Strategy・Observer・Decoratorの5つで、まずはこの5つから押さえるのがおすすめです。ただし、必要になる前に先回りして導入すると過剰設計になりやすいため、使うべき場面の見極め方もあわせて解説します。

デザインパターンの本を読んでも、正直「で、いつ使うの?」となった経験はないでしょうか。私も最初はGoFの23パターンを丸暗記しようとして挫折しました。

あわせて読む

この記事を読めば、まずは実務でよく使われる5パターンから押さえればよいことがわかります。

ただし覚えるだけでは不十分で、「使うべき場面」を誤ると逆にコードが複雑になります。

分類の全体像・実務5パターンのコード例・導入すべき場面と避けるべき場面の見分け方まで、必要な部分だけ拾い読みできる構成にしました。

この記事でわかること

  • デザインパターンとGoF23種類の全体像
  • 3つの分類(生成・構造・振る舞い)の考え方
  • 実務で使用頻度が高い5パターンのJavaコード例
  • 学ぶ際に陥りがちな過剰設計への注意点

Javaデザインパターンとは?GoF23種類の位置づけ

デザインパターンとは、ソフトウェア設計における典型的な問題に対する、再利用可能な解決策の型です。

1994年、4人のエンジニア(通称Gang of Four、略してGoF)が著書「オブジェクト指向における再利用のためのデザインパターン」を発表しました。この著書で、23種類のパターンがまとめられています。

この23種類は、現在も設計を話し合うときの共通の呼び名として多くの現場で使われています。

言語やフレームワークに依存しない普遍的な考え方なので、Javaに限らずTypeScriptやPythonでも同じ名前・同じ考え方のパターンが登場します。

SpringのようなJavaフレームワーク自体が、内部でFactory MethodやTemplate Methodを多用して作られています。

あわせて読む

ただし23種類を全部覚える必要はありません。実務のコードレビューで頻繁に名前が挙がるのは、体感でも5〜7パターン程度です。

まずは全体の分類を押さえてから、頻出パターンに絞って理解を深めるのが挫折しない近道です。

あわせて読む

Javaデザインパターンはどう分類される?

GoFの23パターンは「生成」「構造」「振る舞い」の3グループに分かれます。

どのグループに属するかを知っておくと、初見のパターンでも大まかな役割を推測できるようになります。

生成に関するパターン(5種)

オブジェクトの生成方法を抽象化するグループです。newを直接書くとテストしづらく変更にも弱くなる、という古典的な問題を解決するために生まれました。

Singleton・Factory Method・Abstract Factory・Builder・Prototypeの5つが該当します。

構造に関するパターン(7種)

クラスやオブジェクトの組み合わせ方を扱うグループです。

Adapter・Bridge・Composite・Decorator・Facade・Flyweight・Proxyの7つが含まれます。

互換性のないインターフェースをつなげたり、既存のオブジェクトに機能を追加したりする場面で登場します。

振る舞いに関するパターン(11種)

オブジェクト間の責任分担や通信方法を扱う、最も数の多いグループです。

Strategy・Observer・Command・Iterator・State・Template Method等の11パターンが該当します。

「条件分岐だらけのif文をどう整理するか」という悩みの多くは、このグループのどれかで解決できます。

3つの分類とそれぞれに属する代表的なパターンを図にすると、次のようになります。

GoFデザインパターン23種の3分類と代表的なパターン
分類
扱うこと
代表的なパターン
生成5種
オブジェクトの生成方法
Singleton
Factory Method
構造7種
クラスやオブジェクトの組み合わせ方
Decorator
Adapter
振る舞い11種
オブジェクト間の責任分担や通信方法
Strategy
Observer
NOTE3つを合わせて23種。分類がわかると、初見のパターンでも大まかな役割を推測できる。

Javaデザインパターン一覧|実務で使う5選

23種類のうち、実務のコードで見かける頻度が高いのは次の5パターンです。それぞれ「何を解決するか」から先に押さえると理解が早まります。

Singleton(シングルトン)

クラスのインスタンスをアプリケーション全体で1つだけに制限するパターンです。

設定情報やロガーのように、複数箇所から共有したいが複数生成されると困る対象に使います。

public class AppLogger {
    private static AppLogger instance;
    private AppLogger() {
        // 外部からのインスタンス生成を禁止
    }
    public static synchronized AppLogger getInstance() {
        if (instance == null) {
            instance = new AppLogger();
        }
        return instance;
    }
    public void log(String message) {
        System.out.println(message);
    }
}

Singletonはグローバル状態を増やすためテストがしづらくなる副作用があります。

Spring等のDIコンテナを使っている場合は、自前実装よりも@Componentのデフォルトスコープに任せるほうが実務的です。

Factory Method(ファクトリーメソッド)

オブジェクトの生成処理をメソッドに集約し、呼び出し側から具体的なクラスを隠すパターンです。

以下のコードは、生成処理を1つのstaticメソッドに集めた簡易な形(Simple Factory/staticファクトリーメソッド)です。GoF原典のFactory Methodは、生成を担うメソッドをサブクラスでオーバーライドして、生成するクラスをサブクラスに決めさせる形で、構造が異なります。

条件によって生成するクラスを切り替える必要が出た時点で導入すると効果的です。

interface Notifier {
    void send(String message);
}
class EmailNotifier implements Notifier {
    public void send(String message) { System.out.println("Email: " + message); }
}
class SlackNotifier implements Notifier {
    public void send(String message) { System.out.println("Slack: " + message); }
}
class NotifierFactory {
    public static Notifier create(String type) {
        return switch (type) {
            case "email" -> new EmailNotifier();
            case "slack" -> new SlackNotifier();
            default -> throw new IllegalArgumentException("未対応: " + type);
        };
    }
}

Strategy(ストラテジー)

アルゴリズムを別クラスに切り出し、実行時に差し替え可能にするパターンです。

割引計算や料金プランのように、条件分岐が増え続けるロジックの整理に向いています。

interface DiscountStrategy {
    int apply(int price);
}
class NoDiscount implements DiscountStrategy {
    public int apply(int price) { return price; }
}
class TenPercentOff implements DiscountStrategy {
    public int apply(int price) { return price * 9 / 10; }
}
class Order {
    private final DiscountStrategy strategy;
    Order(DiscountStrategy strategy) { this.strategy = strategy; }
    int total(int price) { return strategy.apply(price); }
}

if文で条件を積み重ねる代わりに、条件ごとのクラスを用意して差し替えるだけになります。

新しい割引ルールが増えても、既存クラスを変更せずに追加できるのが利点です。

あわせて読む

Observer(オブザーバー)

あるオブジェクトの状態変化を、複数の監視役(オブザーバー)へ自動的に通知するパターンです。イベント駆動の仕組みやpub/sub型の設計でよく使われます。

Javaの標準APIではPropertyChangeListener等に考え方が組み込まれています。

シンプルな自前実装であれば、通知を受け取る側のListenerインターフェースと、状態変化を検知して通知する側のクラスを用意するだけで実現できます。

interface Listener {
    void onChange(String newValue);
}

class TemperatureSensor {
    private final List<Listener> listeners = new ArrayList<>();

    void addListener(Listener listener) {
        listeners.add(listener);
    }

    void setTemperature(String newValue) {
        for (Listener listener : listeners) {
            listener.onChange(newValue);
        }
    }
}

class AlertLogger implements Listener {
    public void onChange(String newValue) {
        System.out.println("温度が変化しました: " + newValue);
    }
}

TemperatureSensorに複数のListenerを登録しておけば、状態が変わるたびに全員へ自動で通知が飛びます。通知先を増やしてもTemperatureSensor自体は変更不要です。

Decorator(デコレーター)

既存のオブジェクトを変更せずに、新しい機能を後から追加するパターンです。

認証チェックやロギングのように「本来の処理の前後に何かを挟みたい」場面に向いています。

JavaのI/Oクラス(BufferedReaderがReaderを包む構造等)が代表例です。

自前で実装する場合は、元のオブジェクトと同じインターフェースを実装した「包む」クラスを用意します。

interface Coffee {
    String getDescription();
    int getCost();
}

class SimpleCoffee implements Coffee {
    public String getDescription() { return "コーヒー"; }
    public int getCost() { return 300; }
}

abstract class CoffeeDecorator implements Coffee {
    protected final Coffee decorated;
    CoffeeDecorator(Coffee decorated) {
        this.decorated = decorated;
    }
}

class MilkDecorator extends CoffeeDecorator {
    MilkDecorator(Coffee decorated) {
        super(decorated);
    }
    public String getDescription() { return decorated.getDescription() + " + ミルク"; }
    public int getCost() { return decorated.getCost() + 50; }
}

MilkDecoratorはCoffeeを実装しているので、元のSimpleCoffeeを直接書き換えずに機能(説明文と価格)を上乗せできます。トッピングが増えても、既存クラスは触らずに新しいDecoratorクラスを追加するだけで済みます。

new MilkDecorator(new SimpleCoffee())のgetDescription()とgetCost()を呼んで「説明: 価格円」の形で表示するとコーヒー + ミルク: 350円となり、元のSimpleCoffeeのクラス定義を変更せずに機能を上乗せできていることが確認できます。

Decoratorで処理が上乗せされる流れ
1
呼び出し側 → MilkDecoratorMilkDecoratorのメソッドを呼ぶgetCost() / getDescription()。中身が何かは気にしない
2
MilkDecorator → SimpleCoffee包んでいるSimpleCoffeeの同じメソッドをそのまま呼ぶ
3
SimpleCoffee(元のまま)元の値を返すgetCost() → 300 / getDescription() → "コーヒー"
4
MilkDecorator(包む側)受け取った値に上乗せする300 + 50 = 350 / "コーヒー" + " + ミルク"
5
MilkDecorator → 呼び出し側上乗せした結果が返る表示は「コーヒー + ミルク: 350円」
NOTESimpleCoffeeは書き換えていない。上乗せはすべてMilkDecorator側で行う。

Javaデザインパターンを学ぶメリットと注意点

デザインパターンを知っておく一番のメリットは、チーム内の会話が速くなることです。

「ここはStrategyで切り出そう」の一言で設計意図が伝わるようになります。

コードレビューでも、パターン名を共通言語として使えると議論が具体的になります。

過剰設計(オーバーエンジニアリング)に気をつける

覚えたてのパターンを何にでも当てはめたくなる時期は、誰にでもあります。

私自身、将来の拡張に備えてStrategyパターンを導入したことがありますが、想定していた拡張のケースは結局来ませんでした。

「YAGNI(You Ain't Gonna Need It)」という原則を知らなかった頃の失敗です。

トム
トム

先回りして拡張性を用意しておくのは悪いことではないですよね?

トム
トム

今すぐ必要かどうかで判断してください。将来の予測は外れることが多いです。

単純な処理にSingletonやFactoryを持ち込むと、クラス数だけ増えて可読性が下がることも珍しくありません。

判断基準はシンプルです。分岐や生成ロジックが「今後増える見込みがあるか」で決めます。

増える見込みがないなら素直にif文やnewで書き、実際に複雑さが出てきた時点でパターンを導入すれば十分です。

パターンを導入すべき場面・避けるべき場面
USE / 導入すべき場面分岐や生成が今後も増える同じ条件分岐や生成ロジックが今後も増えていく見込みがある/複数箇所から同じ考え方を再利用したい
SKIP / 避けるべき場面増える見込みがない分岐や生成が今後も増える見込みがない/「念のため」という理由だけで先回りしたい
NOTE判断の軸は「今後増える見込みがあるか」。見込みがなければ素直にif文やnewで書く。

Javaデザインパターンが学べるおすすめの本

Java向けの入門書としては、結城浩氏の「Java言語で学ぶデザインパターン入門 第3版」が定番です。

旧版(増補改訂版)を、ジェネリクス・ラムダ式・enum型等の現代のJava言語でリニューアルした版で、2026年9月時点で最新の第3版です。

2026年10月18日時点でAmazon.co.jpには85件のレビューが寄せられており、関心の高さがうかがえます。

読み方のコツ

23パターンそれぞれにサンプルコードが付いています。

手を動かしてコードを書いたあとに読むと理解が定着しやすいと言われています。

あわせて読む

よくある質問(FAQ)

Javaのデザインパターンについて、読者からよく聞かれる質問をまとめました。覚える範囲の目安から、他の設計思想との関係まで扱っています。細かい実装や根拠は各見出しの本文もあわせて確認してください。

Q1. デザインパターンは全部覚える必要がありますか?

A1. いいえ。実務でよく使われるのはSingleton・Factory Method・Strategy・Observer・Decorator等の一部です。まずはこの記事で紹介した5〜7パターンから覚えれば十分です。

Q2. GoFとは何の略ですか?

A2. 「Gang of Four」の略で、デザインパターンをまとめた4人のエンジニアの通称です。書籍「オブジェクト指向における再利用のためのデザインパターン」の著者を指します。

Q3. デザインパターンとオブジェクト指向の違いは何ですか?

A3. オブジェクト指向はクラス・継承・ポリモーフィズムといった言語機能そのものを指します。デザインパターンは、それらの機能を使って典型的な問題を解決する設計の型という位置づけです。

Q4. デザインパターンはJava以外の言語でも使えますか?

A4. はい。GoFのパターンは言語非依存の設計思想なので、TypeScriptやPython、Goでも同じ名前・同じ考え方で登場します。

Q5. Springフレームワークとデザインパターンは関係がありますか?

A5. あります。SpringのDIコンテナはBeanの生成を担うファクトリーの仕組みで、@Beanメソッドはファクトリーメソッドとして呼ばれます。デフォルトのシングルトンスコープは「コンテナごと・Beanごとに1つ」を共有する仕組みで、GoFのSingletonとは別物です。

Q6. デザインパターンを使うとコードは必ず良くなりますか?

A6. 必ずではありません。単純な処理に無理に適用すると、クラス数が増えるだけで可読性が下がることがあります。複雑さが実際に出てきてから導入するのが実務的です。

Q7. ObserverとDecoratorは組み合わせて使えますか?

A7. はい、組み合わせて使えます。Observerは状態変化の通知、Decoratorは機能の追加という別々の役割を持つため、たとえば温度センサーの通知処理にログ出力機能をDecoratorで追加する、といった組み合わせが可能です。ただし両方を同時に導入すると設計が複雑になりやすいため、実際に両方の要件が出てきてから組み合わせることをおすすめします。

あわせて読みたい

まとめ

Javaのデザインパターンは、23種類を丸暗記するものではなく、必要になったときに引き出せる道具箱として持っておくのが現実的です。要点を整理します。

  • デザインパターンは「生成」「構造」「振る舞い」の3分類で全体像を押さえる
  • 実務ではSingleton・Factory Method・Strategy・Observer・Decoratorの使用頻度が高い
  • 覚えるより先に「何を解決するパターンか」を理解する
  • 複雑さが実際に出てきてから導入し、過剰設計を避ける

まずは自分のコードの中で「同じようなif分岐が増え続けている箇所」を1つ探し、Strategyパターンで書き直してみるところから始めてみてください。

REVISIONS / 改訂履歴
REV.DATE内容
42026-10-16図解を描き直し(図面のデザインにそろえた)
32026-10-04記載内容の事実確認と修正
22026-09-292026年9月時点の情報で全体を見直し(古い記述を1件更新)
12026-09-05初版
NEXT READ本棚から1本

AIで開発を組み直すなら、まずこの5冊から

入門・実践・設計まで、Claude Codeの本をレベル別に5冊選んで比べました。

→ おすすめ5冊を見る

  • この記事を書いた人
  • 最新記事

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

𝕏

Java入門