Adapterパターンとは
Adapterパターンは、GoF(Gang of Four)によって定義されたデザインパターンの一つで、既存のクラスのインターフェースを、クライアントが期待する別のインターフェースに適合させるためのものです。このパターンを使用することで、既存のクラスに手を加えることなく、異なるインターフェースを持つクラスとして利用できるようになります。
Adapterパターンは、主に以下の二つの手法で実現されます。
1. 継承を利用したAdapter
2. 委譲を利用したAdapter
継承を利用したAdapter
継承を利用したAdapterは、既存のクラス(Adaptee)を継承し、必要なインターフェース(Target)を実装するAdapterクラスを作成します。これにより、AdapterクラスはAdapteeクラスの機能を利用しつつ、クライアントが期待するインターフェースを提供できます。
サンプルプログラム
以下の例では、`Product`クラスが既存のクラスで、修正ができないとします。この`Product`クラスの価格を取得する`getCost()`メソッドを、`getPrice()`メソッドとして利用したい開発者がいるとします。このとき、`ProductAdapter`というAdapterクラスを作成することで、`Product`クラスを修正せずに、異なるインターフェースで`Product`クラスを利用できるようになります。
java
// 既存のクラス(Adaptee)
class Product {
public int getCost() {
return 100;
}
}
// ターゲットインターフェース
interface ProductPrice {
int getPrice();
}
// Adapterクラス
class ProductAdapter extends Product implements ProductPrice {
@Override
public int getPrice() {
return getCost();
}
}
public class Main {
public static void main(String[] args) {
ProductPrice productPrice = new ProductAdapter();
System.out.println(productPrice.getPrice()); // Output: 100
}
}
mermaid
classDiagram
class Target{
<
>
requiredMethod()
}
class Adapter{
requiredMethod()
}
class Adaptee{
oldMethod()
}
Target <|-- Adapter : implements
Adapter --|> Adaptee : extends
Target : ProductPrice
Target : getPrice()
Adapter : ProductAdapter
Adapter : getPrice()
Adaptee : Product
Adaptee : getCost()
委譲を利用したAdapter
委譲を利用したAdapterは、既存のクラス(Adaptee)のインスタンスをAdapterクラス内に持ち、そのインスタンスを利用して必要なインターフェース(Target)を提供します。この手法では、継承を使用せずにAdapterを実現できるため、より柔軟な設計が可能です。
サンプルプログラム
java
// 既存のクラス(Adaptee)
class Product {
public int getCost() {
return 100;
}
}
// ターゲットインターフェース
interface ProductPrice {
int getPrice();
}
// Adapterクラス
class ProductAdapter implements ProductPrice {
private Product product;
public ProductAdapter(Product product) {
this.product = product;
}
@Override
public int getPrice() {
return product.getCost();
}
}
public class Main {
public static void main(String[] args) {
Product product = new Product();
ProductPrice productPrice = new ProductAdapter(product);
System.out.println(productPrice.getPrice()); // Output: 100
}
}
mermaid
classDiagram
class Target{
<>
requiredMethod()
}
class Adapter{
requiredMethod()
}
class Adaptee{
oldMethod()
}
Target <|-- Adapter : implements
Adapter --* Adaptee : Aggregation
Target : ProductPrice
Target : getPrice()
Adapter : ProductAdapter
Adapter : getPrice()
Adaptee : Product
Adaptee : getCost()
※クラス図において、extendsはimplementsでも良い。
このように、Adapterパターンは、既存のコードを修正することなく、異なるインターフェースを必要とする場合に非常に役立つデザインパターンです。継承と委譲の両方の手法を理解し、状況に応じて適切な方法を選択することが重要です。