Javaの基礎を学んだあと、より実践的かつ保守性の高いコードを書くためには「オブジェクト指向設計の深化」が欠かせません。
本記事では、現場で頻出する代表的なデザインパターン(Singleton、Factory、Observer)と、既存コードを改善するリファクタリングの技法について、Javaを使って詳しく解説します。

1. デザインパターン:再利用可能な設計の知恵
1-1. Singletonパターン:唯一のインスタンスを保証する
Singleton(シングルトン)パターンは、あるクラスのインスタンスが常に1つだけであることを保証したい場合に使用されます。
設定情報やログ記録クラスなど、アプリケーション全体で共有されるべきオブジェクトに適しています。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Javaではスレッドセーフを意識した実装が求められるため、synchronized
や静的初期化
の活用が鍵となります。
1-2. Factoryパターン:オブジェクト生成の柔軟性を高める
Factory(ファクトリ)パターンは、オブジェクトの生成処理をカプセル化するパターンです。
具体的なクラス名に依存せず、抽象インターフェースを返すことで、拡張性の高いコード設計が可能になります。
interface Product {
void use();
}
class ProductA implements Product {
public void use() {
System.out.println("Product A used");
}
}
class ProductFactory {
public static Product createProduct(String type) {
if (type.equals("A")) {
return new ProductA();
}
throw new IllegalArgumentException("Unknown type");
}
}
このように、実装クラスの変更や追加がしやすくなるため、保守性が飛躍的に向上します。
1-3. Observerパターン:イベント駆動の鍵を握る
Observer(オブザーバー)パターンは、あるオブジェクトの状態変化を複数のオブジェクトに通知する仕組みです。
GUIイベント、通知システム、ストック価格の更新などで活用されます。
interface Observer {
void update(String message);
}
class ConcreteObserver implements Observer {
public void update(String message) {
System.out.println("Received: " + message);
}
}
class Subject {
private List<Observer>
observers = new ArrayList<>();
public void addObserver(Observer o) {
observers.add(o);
}
public void notifyObservers(String msg) {
for (Observer o : observers) {
o.update(msg);
}
}
}
オブザーバーは疎結合を促し、イベント指向のシステム設計において極めて有効です。
2. リファクタリング:既存コードを蘇らせる技法
リファクタリングとは、コードの外部仕様を変えずに内部構造を改善する手法です。読みやすく、バグが入りにくいコードを保つためには不可欠です。
2-1. メソッドの抽出(Extract Method)
大きすぎるメソッドは理解しづらくなります。
ロジックのまとまりごとにメソッドに切り出すことで、見通しの良いコードになります。
// Before public void printReport() { System.out.println("Title"); System.out.println("Data: " + fetchData()); } // After public void printReport() { printTitle(); printData(); } private void printTitle() { System.out.println("Title"); } private void printData() { System.out.println("Data: " + fetchData()); }
2-2. 条件文の簡略化(Decompose Conditional)
複雑な条件文は、小さなメソッドに分解し、意味を明示することで理解が容易になります。
// Before
if (date.before(summerStart) || date.after(summerEnd)) {
charge = winterRate * quantity + winterServiceCharge;
} else {
charge = summerRate * quantity;
}
// After
if (isWinter(date)) {
charge = winterRate * quantity + winterServiceCharge;
} else {
charge = summerRate * quantity;
}
private boolean isWinter(Date date) {
return date.before(summerStart) || date.after(summerEnd);
}
このような小さな改善の積み重ねが、長期的なコード品質に大きな差を生み出します。
まとめ:実務力を高める設計思考の習得
Javaで実務的なソフトウェアを開発するためには、単にコードを書く力だけでなく、再利用可能で保守性の高い設計力が求められます。
デザインパターンはその設計力の基礎となり、リファクタリングは継続的な品質改善の手段です。
本記事で紹介した内容は、いずれも現場で頻出する重要技法ですので、ぜひ実践を通じて自分の武器にしてください。