1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【デザインパターン】 アダプタパターン解説(Flutter / Android 実例付き)

Posted at

1. パターンの意図

アダプタ(Adapter)パターン は、
既存のクラスやインターフェースをクライアントが期待する形式に変換する デザインパターンです。

解決する問題

  • ライブラリや既存コードのインターフェースが自分のプロジェクトと合わない
  • 外部 API とアプリ内のモデルを変換する必要がある
  • 「インターフェース不一致」を吸収したい

ポイント

  • 電源変換プラグのイメージ:合わない形を変換して使えるようにする
  • クライアント側は「変換されていること」を意識せず利用できる

2. UML 図

  • Target:クライアントが期待するインターフェース
  • Adaptee:既存のクラス(インターフェースが合わない)
  • Adapter:Adaptee を Target に適合させる役割
  • Client:Target に依存し、Adapter を通じて Adaptee を使う

3. Flutter / Dart 実装例

3.1 期待するインターフェース(Target)

abstract class JsonParser {
  Map<String, dynamic> parse(String text);
}

3.2 既存クラス(Adaptee)

class LegacyXmlParser {
  Map<String, dynamic> parseXml(String xml) {
    // XML を JSON っぽく変換(簡略化例)
    return {"data": xml};
  }
}

3.3 アダプタ

class XmlToJsonAdapter implements JsonParser {
  final LegacyXmlParser _xmlParser;

  XmlToJsonAdapter(this._xmlParser);

  @override
  Map<String, dynamic> parse(String text) {
    return _xmlParser.parseXml(text);
  }
}

3.4 利用例

void main() {
  JsonParser parser = XmlToJsonAdapter(LegacyXmlParser());
  var result = parser.parse("<data>hello</data>");
  print(result); // {data: <data>hello</data>}
}

4. Android / Kotlin 実装例

4.1 Target

interface JsonParser {
    fun parse(text: String): Map<String, Any>
}

4.2 Adaptee

class LegacyXmlParser {
    fun parseXml(xml: String): Map<String, Any> {
        return mapOf("data" to xml)
    }
}

4.3 Adapter

class XmlToJsonAdapter(private val xmlParser: LegacyXmlParser) : JsonParser {
    override fun parse(text: String): Map<String, Any> {
        return xmlParser.parseXml(text)
    }
}

4.4 利用例

fun main() {
    val parser: JsonParser = XmlToJsonAdapter(LegacyXmlParser())
    val result = parser.parse("<data>hello</data>")
    println(result) // {data=<data>hello</data>}
}

5. メリット / デメリット

メリット

  • 既存クラスを修正せずに再利用できる
  • 新旧インターフェースの橋渡しが可能
  • クライアントは一貫したインターフェースで利用可能

デメリット

  • クラス数が増える
  • アダプタを乱用すると「変換だらけ」で複雑になる

6. 実務ユースケース

Flutter

  • Platform Channel:iOS/Android ネイティブ API を Dart の形式に変換
  • 外部 API レスポンス変換:REST/GraphQL レスポンスをアプリ内モデルに適合
  • レガシーコードラップ:旧サービスのクラスを新しいインターフェースに統一

Android (Kotlin)

  • RecyclerView.Adapter(UIコンポーネントのデータ変換)
  • API モデル変換(DTO → Domain モデル)
  • Java ライブラリのラップ(Java API を Kotlin フレンドリーに変換)

7. 実装上の注意点

Flutter / Dart

  • fromJsontoEntityAdapter 的責務として明確化すると整理しやすい
  • Repository 層で DTO ⇔ Domain 変換に多用される

Android / Kotlin

  • Adapter の乱用で 「変換クラスだらけ」 にならないように注意
  • Mapper / Converter との責務分離を意識する

8. どんなときに使う?

  • 外部ライブラリを修正せずに利用したい
  • API / データモデルをプロジェクト仕様に合わせたい
  • クライアントは「新しい統一 API」に依存させたい

まとめ

  • アダプタパターンは「インターフェース不一致を吸収するための変換器」
  • Flutter では Platform Channel、Android では RecyclerView.Adapter が代表例
  • 既存コードを変更できない/したくないときに特に有効
  • 過剰に増やさず、責務を明確化したアダプタ設計がベストプラクティス
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?