Flutter初心者の学習記録 第6回:抽象クラスとインターフェース
抽象クラスとインターフェース: Flutterでのオブジェクト指向プログラミングの基礎

こんにちは、ジミーです!Flutterアプリ開発において、コードの再利用性と保守性を高めるためには、オブジェクト指向プログラミングの概念を理解することが重要です。今回は、Dartにおける「抽象クラス」と「インターフェース」について掘り下げていきます。これらの概念を理解し活用することで、より柔軟で堅牢なFlutterアプリケーションを構築できるようになります。
抽象クラスとは?
抽象クラス(Abstract Class)は、インスタンス化できないクラスです。抽象クラスの主な目的は、共通の振る舞いを定義し、それを継承するサブクラスに実装を委ねることです。
Dartでは、abstract
キーワードを使って抽象クラスを定義します:
abstract class Animal {
// 抽象メソッド(実装なし)
void makeSound();
// 通常のメソッド(実装あり)
void breathe() {
print('呼吸中...');
}
}
抽象クラスの特徴:
- インスタンス化できない(
new Animal()
とは書けない) - 抽象メソッド(実装のないメソッド)を持つことができる
- 通常のメソッド(実装のあるメソッド)も持つことができる
- サブクラスは抽象メソッドを必ず実装する必要がある
インターフェースとは?
Dartには、他の言語のような明示的なインターフェースキーワードはありません。代わりに、すべてのクラスが暗黙的にインターフェースとして機能します。クラスをimplements
キーワードで実装することで、そのクラスのインターフェースを実装できます。
class Flyable {
void fly() {
print('飛行中...');
}
}
class Bird implements Flyable {
@override
void fly() {
print('鳥が飛んでいます');
}
}
インターフェースの特徴:
- クラスを
implements
することでインターフェースとして使用する - 実装するクラスは、インターフェースのメソッドをすべてオーバーライドする必要がある
- 複数のインターフェースを実装できる
抽象クラスとインターフェースの違い
特徴 | 抽象クラス | インターフェース |
---|---|---|
目的 | コードの再利用と共通の振る舞いの定義 | 異なるクラス間での共通の振る舞いの保証 |
実装 | メソッドの実装を持つことができる | Dartでは暗黙的に使用(クラスをimplements) |
継承 | 単一継承のみ | 複数実装可能 |
使用シーン | 密接に関連したクラス間での機能共有 | 異なるクラス階層でも同じ振る舞いを保証したい場合 |
Flutterでの実践例
抽象クラスの活用例
UIコンポーネントの基本機能を抽象クラスで定義する例:
abstract class BaseScreen {
void initState();
void dispose();
// 共通の振る舞い
void showLoading() {
print('ローディング表示中...');
}
void hideLoading() {
print('ローディング非表示...');
}
}
class HomeScreen extends BaseScreen {
@override
void initState() {
print('HomeScreen初期化');
}
@override
void dispose() {
print('HomeScreenリソース解放');
}
}
インターフェースの活用例
異なるデータソースでも同じ操作を保証する例:
class DataRepository {
Future<List<String>> fetchData() async {
return ['データ1', 'データ2'];
}
Future<bool> saveData(String data) async {
return true;
}
}
class ApiService implements DataRepository {
@override
Future<List<String>> fetchData() async {
// APIからデータを取得する実装
return ['API_データ1', 'API_データ2'];
}
@override
Future<bool> saveData(String data) async {
// APIにデータを保存する実装
return true;
}
}
class LocalStorage implements DataRepository {
@override
Future<List<String>> fetchData() async {
// ローカルストレージからデータを取得する実装
return ['ローカル_データ1', 'ローカル_データ2'];
}
@override
Future<bool> saveData(String data) async {
// ローカルストレージにデータを保存する実装
return true;
}
}
Flutter/Dartのmixin
もマスターしよう
Dartには、抽象クラスとインターフェースに加えて、mixin
という機能もあります。これは複数のクラスで振る舞いを共有するための強力な仕組みです。
mixin LoggableMixin {
void log(String message) {
print('ログ: $message');
}
}
class UserRepository with LoggableMixin {
void createUser() {
log('ユーザー作成');
// ユーザー作成のロジック
}
}
mixin
は、with
キーワードを使って既存のクラスに機能を追加するのに使用します。継承とは異なり、複数のmixin
を組み合わせることができます。
まとめ
抽象クラスとインターフェースは、Flutterアプリケーションの設計において非常に重要な概念です。抽象クラスは共通の実装と構造を提供し、インターフェースは異なるクラス間で一貫した振る舞いを保証します。
これらの概念を適切に活用することで:
- コードの再利用性が向上する
- 保守性の高いコードが書ける
- テストがしやすくなる
- 依存性の逆転原則などの設計原則に従った実装ができる
次回は、これらの概念を活用した実際のFlutterアプリケーションの設計パターンについて解説していきます。お楽しみに!
サンプルプロジェクト
最後に、上記の概念を理解するための簡単なFlutterプロジェクト例を示します:
// abstract_interface_demo.dart
// 抽象クラス
abstract class BaseWidget {
void render();
void update() {
print('ウィジェットを更新中...');
}
}
// インターフェース
class Animatable {
void animate() {
print('アニメーション実行');
}
}
// mixin
mixin ThemableMixin {
void applyTheme(String theme) {
print('テーマ適用中: $theme');
}
}
// 抽象クラスを継承
class Button extends BaseWidget {
@override
void render() {
print('ボタンをレンダリング');
}
}
// 抽象クラスを継承 + インターフェースを実装
class AnimatedButton extends BaseWidget implements Animatable {
@override
void render() {
print('アニメーションボタンをレンダリング');
}
@override
void animate() {
print('ボタンアニメーション実行');
}
}
// 抽象クラスを継承 + mixinを使用
class ThemedButton extends BaseWidget with ThemableMixin {
@override
void render() {
print('テーマ付きボタンをレンダリング');
}
}
// メイン実行例
void main() {
final button = Button();
button.render(); // ボタンをレンダリング
button.update(); // ウィジェットを更新中...
final animatedButton = AnimatedButton();
animatedButton.render(); // アニメーションボタンをレンダリング
animatedButton.animate(); // ボタンアニメーション実行
final themedButton = ThemedButton();
themedButton.render(); // テーマ付きボタンをレンダリング
themedButton.applyTheme('ダーク'); // テーマ適用中: ダーク
}
このサンプルコードをDartPadやお手持ちのFlutterプロジェクトで試してみて、概念の理解を深めてください。
オブジェクト指向プログラミングの基礎を理解することで、より良いFlutterアプリケーションを作成する一歩を踏み出しましょう!