Javaでよく使うデザインパターン
Javaで開発する際には、設計パターンを活用することで、可読性やメンテナンス性を高めることができます。本記事では、Javaでよく使う設計パターンについて解説します。
1. Singleton パターン
Singletonパターンとは、クラスのインスタンスが一つしか存在しないことを保証する設計パターンです。ブロッキングIOや、共有のキャッシュ、ロギングなどによく使用されます。
以下は、Singletonパターンの実装例です。
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Singletonパターンでは、インスタンスが一つしか存在しないことを保証するために、以下のような特徴があります。
- クラス内部に、インスタンスを保持するためのprivateコンストラクタが定義されている。
- クラス内部で、インスタンスを生成し、保存するstatic変数が定義されている。
- インスタンスを返却するstaticメソッドが定義されている。
2. Factory Method パターン
Factory Method パターンとは、オブジェクトの生成方法を決定する抽象クラスを定義し、サブクラスで具体的なオブジェクトの生成方法を決定し、抽象クラスで提供されるメソッドをオーバーライドすることで、柔軟で拡張性のある設計を実現するパターンです。
以下は、Factory Method パターンの実装例です。
abstract class Product {
abstract void use();
}
class ConcreteProduct extends Product {
void use() {
System.out.println("Using ConcreteProduct");
}
}
abstract class Factory {
public abstract Product factoryMethod();
}
class ConcreteFactory extends Factory {
public Product factoryMethod() {
return new ConcreteProduct();
}
}
Factory Method パターンでは、以下のような特徴があります。
- オブジェクトの生成方法を決定する抽象クラスが定義されている。
- 具体的なオブジェクト生成方法を決定するサブクラスが定義されている。
- 抽象クラスで提供されるメソッドをオーバーライドすることで、柔軟で拡張性のある設計を実現する。
3. Observer パターン
Observer パターンとは、オブジェクト間の関係性を、あるオブジェクトの状態変化を観測することで、自動的に反映させるための設計パターンです。GUIアプリケーションなどでよく使用されます。
以下は、Observer パターンの実装例です。
interface Observer {
void update();
}
interface Subject {
void attach(Observer o);
void detach(Observer o);
void notifyObservers();
}
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer o) {
observers.add(o);
}
public void detach(Observer o) {
observers.remove(o);
}
public void notifyObservers() {
for (Observer o : observers) {
o.update();
}
}
}
class ConcreteObserver implements Observer {
public void update() {
System.out.println("Update");
}
}
Observer パターンでは、以下のような特徴があります。
- オブジェクトの状態変化を観測するオブジェクトが定義されている。
- 観測対象のオブジェクトに対して、自身を登録するためのメソッドが定義されている。
- 観測対象のオブジェクトが状態が変化すると、登録されたオブジェクトに自動的に通知する。
4. Strategy パターン
Strategy パターンとは、アルゴリズムやロジックを取り替えることで、柔軟で拡張性のある設計を実現するための設計パターンです。Webアプリケーションなどでよく使用されます。
以下は、Strategy パターンの実装例です。
interface Strategy {
void execute();
}
class ConcreteStrategyA implements Strategy {
public void execute() {
System.out.println("Strategy A");
}
}
class ConcreteStrategyB implements Strategy {
public void execute() {
System.out.println("Strategy B");
}
}
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
Strategy パターンでは、以下のような特徴があります。
- アルゴリズムやロジックを取り替えることで、柔軟で拡張性のある設計を実現するための設計パターンです。
- 変更されうる部分を抽象化し、インターフェース(Strategy)にまとめて定義されている。
- 実装クラス(ConcreteStrategy)は処理を実装するためのもので、いくつかのアルゴリズムが存在する。
- Contextクラスはこのインターフェース(Strategy)を使用する部分で、ConcreteStrategyで具体化したアルゴリズムの中から必要なものを選択することが可能です。
5. Adapter パターン
Adapter パターンとは、既存のクラスに不足している機能を付加し、インタフェースを統一することで、異なるオブジェクトでも同じメソッドを使用できるようにする設計パターンです。既存のコードの改変を行わずに、新たに機能を追加することが可能です。
以下は、Adapter パターンの実装例です。
interface Target {
void targetMethod();
}
class Adapter {
Adaptee adaptee = new Adaptee();
void adapterMethod() {
adaptee.adapteeMethod();
}
}
class Adaptee {
void adapteeMethod() {
System.out.println("Adaptee Method");
}
}
class ConcreteTarget implements Target {
public void targetMethod() {
System.out.println("Target Method");
}
}
Adapter パターンでは、以下のような特徴があります。
- 既存のクラスに不足している機能を付加し、インタフェースを統一することで、異なるオブジェクトでも同じメソッドを使用できるようにする設計パターンです。
- Adapterクラスは、Targetインタフェースを実装していますが、内部的にはAdapteeを使用してアダプターの機能を実現しています。
- Adapteeクラスは、既存のクラスです。
- Targetインタフェースは、新しいオブジェクトを実装することで、AdapterクラスがAdapteeとTargetとのインタフェースの間に調整をかけていることを示しています。
まとめ
本記事ではJavaでよく使うデザインパターンについて解説しました。Singleton、Factory Method、Observer、Strategy、Adapterの5つの設計パターンを紹介しました。それぞれの特徴や実装例を示し、効果的な開発を行うために知っておくべき内容をまとめました。
また、以下に参考リンクを掲載しておりますので、より詳細な内容や応用例については、リンクを参照してください。