システム開発を進める中で、「既存の便利なクラスがあるけれど、今のインターフェースと型が合わない」という場面に遭遇することがあります。そんな時に役立つのがAdapter(アダプター)パターンです。
Adapterパターンとは?
Adapterパターンは、「互換性のないインターフェースを持つクラス同士を繋ぐ」ためのデザインパターンです。
現実世界の「電源アダプター」をイメージすると分かりやすいでしょう。日本のコンセント(インターフェースA)に海外の家電(インターフェースB)を繋ぐために、変換アダプターを介するのと全く同じ仕組みです。
登場人物(役割)
Adapterパターンには主に4つの役割が登場します。
- Target(ターゲット): クライアントが今まさに利用したいインターフェース。
- Client(クライアント): Targetインターフェースを利用して処理を行う側。
- Adaptee(アダプティー): すでに存在しているが、インターフェースが適合しないクラス(適合される側)。
- Adapter(アダプター): AdapteeをTargetに適合させるための「橋渡し役」。
C#による実装コード例
ここでは、「古いレガシーな印刷クラス」を、新しい標準的な「ITargetインターフェース」で利用できるようにする例を紹介します。
1. Target(利用したいインターフェース)
C#
public interface ITarget
{
void PrintNormal(string message);
}2. Adaptee(互換性のない既存クラス)
既存のライブラリや古いコードを想定しています。メソッド名などが異なりますが、これ自体には手を加えられない(または加えたくない)状況です。
C#
public class LegacyPrinter
{
// メソッド名も使い方もTargetとは異なっている
public void ShowWithBrackets(string s)
{
Console.WriteLine($"[[ {s} ]]");
}
}3. Adapter(橋渡し役)
ここがパターンの心臓部です。ITargetを実装し、内部でLegacyPrinterを呼び出します。
C#
public class PrinterAdapter : ITarget
{
private readonly LegacyPrinter _legacyPrinter;
public PrinterAdapter(LegacyPrinter legacyPrinter)
{
_legacyPrinter = legacyPrinter;
}
public void PrintNormal(string message)
{
// ターゲットのメソッドが呼ばれたら、内部で古いメソッドに「翻訳」して実行
_legacyPrinter.ShowWithBrackets(message);
}
}4. クライアントでの利用
C#
class Program
{
static void Main()
{
// 1. 本来は使いたかった古いシステム
LegacyPrinter oldSystem = new LegacyPrinter();
// 2. アダプターを介して、新しいインターフェースとして扱う
ITarget printer = new PrinterAdapter(oldSystem);
// 3. クライアントは古いクラスの詳細を知らずに、新しい共通メソッドで呼び出せる
printer.PrintNormal("Hello, Adapter Pattern!");
}
}Adapterパターンを導入するメリット
- 既存コードを汚さない: Adaptee側のソースコードを一切変更せずに、新しいシステムに統合できます。
- 単一責任の原則: インターフェースの変換ロジックをAdapterに閉じ込めることができ、コードの見通しが良くなります。
- テストのしやすさ: アダプターを介することで、モックへの差し替えが容易になり、ユニットテストが書きやすくなります。
まとめ
Adapterパターンは、「古いものを大切にしつつ、新しい仕組みに対応させる」ための非常に実用的なパターンです。サードパーティ製ライブラリのインターフェースが自社プロジェクトと合わない場合などにも非常に有効ですので、ぜひ活用してみてください。

最近のコメント