Menu
Coddy logo textTech

暗黙的インターフェース

CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 46/110。

すべての Dart クラスは自動的にインターフェースを定義するため、完全な実装を持つ具象クラスであっても、あらゆるクラスをインターフェースとして使用できます。これを暗黙的インターフェースと呼びます。

プロパティとメソッドを持つクラスを考えてみましょう:

class Logger {
  String prefix = '[LOG]';
  
  void log(String message) {
    print('$prefix $message');
  }
  
  void clear() {
    print('Clearing logs...');
  }
}

別のクラスが Logger を実装する場合、prefix プロパティを含め、すべてに対して独自の実装を提供しなければなりません。

class FileLogger implements Logger {
  @override
  String prefix = '[FILE]';
  
  @override
  void log(String message) {
    print('$prefix Writing to file: $message');
  }
  
  @override
  void clear() {
    print('Deleting log file...');
  }
}

これは重要なポイントです。implements を使用するとき、あなたは「自分のクラスは同じ形状(同じメソッドとプロパティ)を持つ」と宣言していることになります。コード、コンストラクタ、またはデフォルト値は一切継承しません。インターフェースの構造に一致させることだけを約束しているのです。

これにより、暗黙的なインターフェースは、交換可能なコンポーネントを作成するために強力なものになります。Logger を期待するコードは、その実装が内部でどのように機能するかにかかわらず、そのインターフェースを実装する任意のクラスで動作できます。

challenge icon

チャレンジ

簡単

具象クラスが暗黙的インターフェースとしてどのように機能するかを示す通知システムを構築しましょう。ベースとなる通知クラスを作成し、それをまったく異なる方法で実装することで、implements を使用する場合にすべてのメンバーを自分自身で提供する必要があることを確認します。

コードを2つのファイルに整理します:

  • notification.dart: ここで通知クラスを定義します:
    • Notification クラス:'default' に設定された String channel プロパティ、[channel]: [message] を出力する send(String message) メソッド、および文字列 'Notification ready' を返す getStatus() メソッドを持ちます。
    • EmailNotification クラス:Notificationimplements します。implements を使用しているため、独自の channel プロパティ('email' に設定)、Sending email: [message] を出力する独自の send() メソッド、および 'Email service active' を返す独自の getStatus() メソッドを提供する必要があります。
    • PushNotification クラス:Notificationimplements します。channel'push' に設定し、send()Push alert: [message] を出力するようにし、getStatus()'Push service connected' を返すようにします。
  • main.dart: 通知ファイルをインポートし、異なるクラスが同じ暗黙的インターフェースをまったく異なる動作でどのように実装できるかを示します:
    • EmailNotificationPushNotification のインスタンスを作成します。
    • 各通知について、getStatus() を使用してそのステータスを出力し、次にメッセージ 'Hello World' を指定して send() を呼び出します。
    • 2つの通知の間に空行を出力します。

注意:implements を使用する場合、Notification からコードを継承することはありません。そのクラスが同じ形状(同じプロパティとメソッド)を持つことを約束するだけです。各実装クラスは、独自の完全な実装を提供します。

期待される出力:

Email service active
Sending email: Hello World

Push service connected
Push alert: Hello World

チートシート

Dartでは、すべてのクラスが自動的に暗黙のインターフェースを定義します。これは、完全な実装を持つ具象クラスであっても、任意のクラスをインターフェースとして使用できることを意味します。

クラスが implements を使用する場合、インターフェースのすべてのプロパティとメソッドに対して独自の実装を提供する必要があります。コード、コンストラクタ、またはデフォルト値は継承されません。インターフェースの構造に一致させることだけを約束します。

具象クラスの例:

class Logger {
  String prefix = '[LOG]';
  
  void log(String message) {
    print('$prefix $message');
  }
  
  void clear() {
    print('Clearing logs...');
  }
}

暗黙のインターフェースの実装:

class FileLogger implements Logger {
  @override
  String prefix = '[FILE]';
  
  @override
  void log(String message) {
    print('$prefix Writing to file: $message');
  }
  
  @override
  void clear() {
    print('Deleting log file...');
  }
}

これにより、暗黙のインターフェースは交換可能なコンポーネントを作成するのに強力なものになります。Logger を期待するコードは、内部実装に関係なく、そのインターフェースを実装する任意のクラスで動作します。

自分で試してみよう

import 'notification.dart';

void main() {
  // TODO: EmailNotificationのインスタンスを作成する
  
  // TODO: getStatus()を使用して、メール通知のステータスを表示する
  
  // TODO: メール通知を使用して、メッセージ「Hello World」を送信する
  
  // TODO: 空行を表示する
  
  // TODO: PushNotificationのインスタンスを作成する
  
  // TODO: getStatus()を使用して、プッシュ通知のステータスを表示する
  
  // TODO: プッシュ通知を使用して、メッセージ「Hello World」を送信する
  
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン