Javaにおける委譲パターン:効率的なタスク割り当ての習得
約2分
別名
- ヘルパー
- 代理
委譲デザインパターンの意図
オブジェクトがタスクの責任を別のヘルパーオブジェクトに委譲できるようにします。
委譲パターンの詳細な説明と実世界の例
実世界の例
レストランでは、ヘッドシェフがタスクをスーシェフに委譲します。1人はグリルを担当し、もう1人はサラダを担当し、3人目はデザートを担当します。各スーシェフはそれぞれの分野を専門としており、ヘッドシェフはキッチン全体の管理に集中できます。これは、メインオブジェクトが特定のタスクをそれぞれの専門分野のヘルパーオブジェクトに委譲する委譲デザインパターンを反映しています。
平易な言葉で
委譲は、オブジェクトがタスクをヘルパーオブジェクトに渡すデザインパターンです。
Wikipediaによると
オブジェクト指向プログラミングでは、委譲とは、あるオブジェクト(レシーバー)のメンバ(プロパティまたはメソッド)を別の元のオブジェクト(送信者)のコンテキストで評価することを指します。委譲は、送信オブジェクトを受信オブジェクトに渡すことによって明示的に行うことができます。これは任意のオブジェクト指向言語で行うことができます。または、言語のメンバ検索ルールによって暗黙的に行うことができます。これには、この機能に対する言語サポートが必要です。
Javaにおける委譲パターンのプログラミング例
印刷の例を考えてみましょう。
インターフェースPrinter
と、3つの実装CanonPrinter
、EpsonPrinter
、HpPrinter
があります。
public interface Printer {
void print(final String message);
}
@Slf4j
public class CanonPrinter implements Printer {
@Override
public void print(String message) {
LOGGER.info("Canon Printer : {}", message);
}
}
@Slf4j
public class EpsonPrinter implements Printer {
@Override
public void print(String message) {
LOGGER.info("Epson Printer : {}", message);
}
}
@Slf4j
public class HpPrinter implements Printer {
@Override
public void print(String message) {
LOGGER.info("HP Printer : {}", message);
}
}
PrinterController
は、このインターフェースで処理されるすべての作業を実装するオブジェクトに委譲することにより、Printer
として使用できます。
public class PrinterController implements Printer {
private final Printer printer;
public PrinterController(Printer printer) {
this.printer = printer;
}
@Override
public void print(String message) {
printer.print(message);
}
}
クライアントコードでは、プリンターコントローラーは、作業を委譲するオブジェクトに応じて、メッセージを異なる方法で印刷できます。
public class App {
private static final String MESSAGE_TO_PRINT = "hello world";
public static void main(String[] args) {
var hpPrinterController = new PrinterController(new HpPrinter());
var canonPrinterController = new PrinterController(new CanonPrinter());
var epsonPrinterController = new PrinterController(new EpsonPrinter());
hpPrinterController.print(MESSAGE_TO_PRINT);
canonPrinterController.print(MESSAGE_TO_PRINT);
epsonPrinterController.print(MESSAGE_TO_PRINT);
}
}
プログラム出力
HP Printer:hello world
Canon Printer:hello world
Epson Printer:hello world
委譲パターンの詳細な説明と実世界の例

Javaで委譲パターンを使用する状況
- 継承せずに、あるクラスから別のクラスに責任を渡したい場合。
- 継承ベースではなく、構成ベースの再利用を実現するため。
- 実行時に、いくつかの交換可能なヘルパークラスを使用する必要がある場合。
Javaにおける委譲パターンの実世界の応用
- Javaのjava.awt.eventパッケージ。リスナーがイベントを処理するためによく使用されます。
- JavaのCollections Framework(java.util.Collections)のラッパークラス。他のコレクションオブジェクトに委譲します。
- Spring Frameworkでは、委譲はIoCコンテナーで広範囲に使用されており、Beanがタスクを他のBeanに委譲します。
委譲パターンの利点とトレードオフ
利点
- サブクラス化の削減:オブジェクトは操作を異なるオブジェクトに委譲し、実行時に変更できるため、サブクラス化の必要性が少なくなります。
- 再利用の促進:委譲は、ヘルパーオブジェクトのコードの再利用を促進します。
- 柔軟性の向上:ヘルパーオブジェクトにタスクを委譲することで、実行時にクラスの動作を変更できます。
トレードオフ
- ランタイムオーバーヘッド:委譲は、間接層を追加することがあり、わずかなパフォーマンスコストが発生する可能性があります。
- 複雑さ:委譲を管理するための追加のクラスとインターフェースが必要になるため、設計が複雑になる可能性があります。
関連するJavaデザインパターン
- コンポジット:委譲は、コンポジットパターン内で使用して、コンポーネント固有の動作を子コンポーネントに委譲できます。
- ストラテジー:委譲は、コンテキストオブジェクトがタスクをストラテジーオブジェクトに委譲するストラテジーパターンでよく使用されます。
- https://java-design-patterns.dokyumento.jp/patterns/proxy/:プロキシパターンは、プロキシオブジェクトが別のオブジェクトへのアクセスを制御し、そのオブジェクトに作業を委譲する委譲の形式です。