Javaデザインパターン:一般的な問題解決手法

Javaデザインパターンは、プログラミング上の問題を解決するための一般的な手法を提供します。「デザインパターン」は、特定の種類の問題にも適用できる共通的なソリューションのテンプレートを意味します。この記事では、Javaで使用されるいくつかの一般的なデザインパターンについて説明し、それらがどのように問題を解決するかを説明し、コード例で実例を紹介します。

目次

  1. Singletonパターン
  2. Factoryパターン
  3. Observerパターン
  4. Strategyパターン
  5. Decoratorパターン

1. Singletonパターン

Singletonは、アプリケーション全体で一つのインスタンスしか持たない限定されたリソースを管理したい場合に適用されるデザインパターンです。これは、一度だけ生成され、アプリケーションが終了するまで存続します。

コード例

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

2. Factoryパターン

Factoryパターンは、クライアントからオブジェクト作成のロジックを切り離し、専用の「ファクトリ」クラスを用いてインスタンス化を行うデザインパターンです。

コード例

public interface Animal {
    void speak();
}

public class Dog implements Animal {
    public void speak() {
        System.out.println("Woof!");
    }
}

public class Cat implements Animal {
    public void speak() {
        System.out.println("Meow!");
    }
}

public class AnimalFactory {
    public Animal createAnimal(String type) {
        if ("Dog".equalsIgnoreCase(type)) {
            return new Dog();
        } else if ("Cat".equalsIgnoreCase(type)) {
            return new Cat();
        }
        return null;
    }
}

3. Observerパターン

Observerパターンは、オブジェクト間の1対多の依存関係を作成して、状態の変化があるとオブザーバーに通知されることを可能にするパターンです。

コード例

public interface Observer {
    void update(int value);
}

public class IncrementObserver implements Observer {
    @Override
    public void update(int value) {
        System.out.println("IncrementObserver: " + (value + 1));
    }
}

public class SquareObserver implements Observer {
    @Override
    public void update(int value) {
        System.out.println("SquareObserver: " + (value * value));
    }
}

public class Subject {
    private List<Observer> observers = new ArrayList<Observer>();
    private int value;

    public void attach(Observer observer) {
        observers.add(observer);
    }

    public void setValue(int value) {
        this.value = value;
        notifyObservers();
    }

    private void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(value);
        }
    }
}

4. Strategyパターン

Strategyパターンは、アルゴリズムを個々のオブジェクトにカプセル化し、クライアントと独立して交換可能にすることで、アルゴリズムの選択と実装を柔軟にすることができるパターンです。

コード例

public interface SortStrategy {
    void sort(int[] arr);
}

public class BubbleSortStrategy implements SortStrategy {
    public void sort(int[] arr) {
        // バブルソートアルゴリズムの実装
    }
}

public class MergeSortStrategy implements SortStrategy {
    public void sort(int[] arr) {
        // マージソートアルゴリズムの実装
    }
}

public class SortContext {
    private SortStrategy strategy;

    public void setStrategy(SortStrategy strategy) {
        this.strategy = strategy;
    }

    public void executeStrategy(int[] arr) {
        strategy.sort(arr);
    }
}

5. Decoratorパターン

Decoratorパターンは、既存のオブジェクトの機能を動的に追加することができるデザインパターンです。デコレータクラスは、コンポーネント・インターフェースを実装し、元のオブジェクトをラップして新しい機能を追加します。

コード例

public interface Coffee {
    String getDescription();
    double getCost();
}

public class SimpleCoffee implements Coffee {
    public String getDescription() {
        return "Simple coffee";
    }

    public double getCost() {
        return 1.0;
    }
}

public abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }

    public String getDescription() {
        return decoratedCoffee.getDescription();
    }

    public double getCost() {
        return decoratedCoffee.getCost();
    }
}

public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    public String getDescription() {
        return super.getDescription() + ", with milk";
    }

    public double getCost() {
        return super.getCost() + 0.5;
    }
}

以上が、Javaデザインパターンに関する基礎的な内容です。これらのパターンは、ソフトウェア開発においてプログラミングの複雑性をまとめることができる実用的かつ強力なソリューションを提供しています。学んだ内容を実践に取り入れることで、Javaプログラムをより効率的に作成できるでしょう。