暗黙的インターフェース
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 を期待するコードは、その実装が内部でどのように機能するかにかかわらず、そのインターフェースを実装する任意のクラスで動作できます。
チャレンジ
簡単具象クラスが暗黙的インターフェースとしてどのように機能するかを示す通知システムを構築しましょう。ベースとなる通知クラスを作成し、それをまったく異なる方法で実装することで、implements を使用する場合にすべてのメンバーを自分自身で提供する必要があることを確認します。
コードを2つのファイルに整理します:
notification.dart: ここで通知クラスを定義します:Notificationクラス:'default'に設定されたString channelプロパティ、[channel]: [message]を出力するsend(String message)メソッド、および文字列'Notification ready'を返すgetStatus()メソッドを持ちます。EmailNotificationクラス:Notificationを implements します。implementsを使用しているため、独自のchannelプロパティ('email'に設定)、Sending email: [message]を出力する独自のsend()メソッド、および'Email service active'を返す独自のgetStatus()メソッドを提供する必要があります。PushNotificationクラス:Notificationを implements します。channelを'push'に設定し、send()でPush alert: [message]を出力するようにし、getStatus()が'Push service connected'を返すようにします。
main.dart: 通知ファイルをインポートし、異なるクラスが同じ暗黙的インターフェースをまったく異なる動作でどのように実装できるかを示します:EmailNotificationとPushNotificationのインスタンスを作成します。- 各通知について、
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」を送信する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ