1
0

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開発で、コードの抽象化についてまとめた

Last updated at Posted at 2025-03-25

初めに

Flutter開発をしていると、見やすく、使いやすいコードを書くことに悩むことがあります。
そこで今回は、「プログラミングの抽象化」 という概念を活用し、コードの整理や再利用性を高める方法に挑戦しました。
抽象化とは何かを理解し、実際にFlutterで適用できるサンプルコードを作成して、どのように活用できるのかを整理してみました。

本編

プログラミングにおける抽象化

抽象化とは、複数の具体的なものから共通点を抽出し、汎用的な概念として定義・名付けすることです。
例:ビール、お茶、水などは「飲み物」、おにぎり、ラーメン、パンなどは「食べ物」として抽象化できる

プログラミングにおいての抽象化も、複数のものから共通点を抽出し、概念付けを行います。ここでいう「もの」とは、UIコンポーネントだけでなく、機能、データ管理システム、アルゴリズムなども含まれます。

エンジニアが抽象化する目的は、使用者に複雑な詳細を隠蔽し、シンプルで汎用的に利用できる形にすることです。
例えば、車はタイヤやエンジンなど複数のパーツで構成されていますが、運転者はエンジンの詳細な動作を知らなくても、「アクセルを踏む」「ブレーキをかける」といった基本操作だけで運転できます。これと同じように、プログラミングにおいても抽象化により、細かい実装を隠し、必要な操作だけを提供することで、より扱いやすい形にすることができます。

Flutterにおける抽象化

FlutterはDartというオブジェクト指向プログラミング(OOP)をサポートする言語で開発されており、オブジェクトやクラスを中心に構築されています。クラスやオブジェクトを通じて、現実世界の概念や機能を「具体化」しています。Flutterの開発においては、具体化したUIや機能を抽象化し、それらを組み合わせて開発していきます。

Flutterでなぜ抽象化が必要なのか?

Flutterにおける抽象化の主な目的は以下の通りです:

  • コードの再利用性向上:共通の機能を抽象化することで、重複を減らします
  • 可読性の向上:コードの構造が明確になり、理解しやすくなります
  • 保守性の向上:抽象クラスを変更するだけで、派生クラスにも影響を与えられます
  • テストの容易化:依存関係を分離しやすくなり、テストが容易になります

Flutterでの抽象化例

以下に、具体的な抽象化の手法を3つ紹介します。

  • classを使った例

Flutterでは、同じ種類のUIコンポーネントを何度も作るとコードが冗長になります。
例えば、ボタンのスタイルを統一するために、CustomButton クラスを作成して再利用できるようにします。

//CustomButtonのClass
class CustomButton extends StatelessWidget {
  final String label;
  final VoidCallback onPressed;

  const CustomButton({required this.label, required this.onPressed, super.key});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(label),
    );
  }
}

// 画面内で使うとき
CustomButton(
  label: "OK",
  onPressed: () => print("OK"),
);

CustomButton(
  label: "NO",
  onPressed: () => print("NO"),
);
  • Abstractクラスを使った例

APIの種類が増えてくると、それぞれの処理を個別に書くとコードが複雑になります。
abstract classを使って共通のインターフェースを定義し、それぞれのAPIで実装することで統一的に扱えるようにします。

// **共通のAPI処理を定義**
abstract class ApiService {
  Future<String> fetchData();
}

// **ユーザーAPI(実装クラス)**
class UserAPI implements ApiService {
  @override
  Future<String> fetchData() async {
    await Future.delayed(Duration(seconds: 1)); // 擬似的なAPI待機
    return "ユーザーデータ";
  }
}

// **商品API(実装クラス)**
class ProductAPI implements ApiService {
  @override
  Future<String> fetchData() async {
    await Future.delayed(Duration(seconds: 1)); // 擬似的なAPI待機
    return "商品データ";
  }
}

// **どちらのAPIでも統一的に扱える**
void main() async {
  ApiService userApi = UserAPI();
  ApiService productApi = ProductAPI();

  print(await userApi.fetchData()); // "ユーザーデータ"
  print(await productApi.fetchData()); // "商品データ"
}
  • mixinを使った例

異なるクラスで共通のログ機能を持たせるときに、mixinを使います。
Dartでは、継承(extends)はクラスに一つしか使用できないので、mixinを使ってさらに共通の機能を追加できます。

mixin Logger {
  void log(String message) {
    final time = DateTime.now().toIso8601String();
    print('[$time] $message');
  }
}

class ApiService with Logger {
  Future<void> fetchData() async {
    log("Fetching data...");
    await Future.delayed(Duration(seconds: 2)); // Simulated API call
    log("Data fetched successfully");
  }
}

void main() {
  final apiService = ApiService();
  apiService.fetchData();
}


まとめ

Flutter開発において、抽象化は欠かせない概念であり、コードの設計時には常に意識する必要があります。
今回は、Flutterの抽象化方法において数個の例を出しましたが、Dart公式には、他にもinterfaceクラスやsealdクラスなどあり、学習を進めてそれらついても整理していきたいと思います。

参照

https://dart.dev/language/class-modifiershttps://dart.dev/language/class-modifiers
https://qiita.com/hukusuke1007/items/8fd3411d2ef3c0d18429#comment-4c21f10a0b3c67709695
https://qiita.com/cw-yamada/items/87311da52c85ae4146fa
https://qiita.com/haru-qiita/items/03c15dc759c5675dd608

1
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?