抽象クラスとインタフェース
1 抽象クラス
どのような処理をするかが決まっていない、抽象メソッドを持つクラスを抽象クラスと呼びます。このようなクラスは、継承され、派生クラスでオーバーライドされることによって当該メソッドの実装を果たし、はじめてインスタンス化されます。
(1)抽象メソッド
抽象メソッドは修飾子 abstract で宣言します。
通常のメソッドならば、実際の処理が { } の中に記述されているはずですが、抽象メソッドの場合はセミコロン ; になっています。 抽象メソッドでは、メソッド名と引数、戻り値の型の宣言だけ行います。
抽象メソッドは、実際の処理を記述せず、その入出力だけ宣言したメソッドとも言えます。インスタンス化するには継承して、抽象メソッドをオーバーライドして実装する必要がありますが、そのときシグネチャ(引数とそのデータ型の組)と戻り値型は抽象メソッドと同じである必要があります。
抽象メソッドは、C++ では「純粋仮想関数」といい、ヘッダーファイルでは、修飾子 virtual で宣言して、さらに = 0 を指定します。
通常のメソッドならば、実際の処理が cpp ファイルなどに記述されているはずですが、純粋仮想関数の場合はそれがありません
純粋仮想関数は、実際の処理を記述せず、その入出力だけ宣言した「仮想関数」です。インスタンス化するには継承して、純粋仮想関数をオーバーライドして実装する必要がありますが、そのときシグネチャ(引数とそのデータ型の組)と戻り値型は純粋仮想関数と同じである必要があります。
純粋仮想関数は修飾子 abstract で宣言します。
通常のメソッドならば、実際の処理が { } の中に記述されているはずですが、純粋仮想関数の場合はセミコロン ; になっています。 抽象メソッドでは、メソッド名と引数、戻り値の型の宣言だけ行います。
抽象メソッドは、実際の処理を記述せず、その入出力だけ宣言したメソッドとも言えます。インスタンス化するには継承して、抽象メソッドをオーバーライドして実装する必要がありますが、そのときシグネチャ(引数とそのデータ型の組)と戻り値型は抽象メソッドと同じである必要があります。
抽象メソッドは修飾子 MustOverride で宣言します。
通常のメソッドならば、実際の処理が記述されているはずですが、抽象メソッドの場合はメソッド名と引数、戻り値の型の宣言だけ行います。
抽象メソッドは、実際の処理を記述せず、その入出力だけ宣言したメソッドとも言えます。インスタンス化するには継承して、抽象メソッドをオーバーライドして実装する必要がありますが、そのときシグネチャ(引数とそのデータ型の組)と戻り値型は抽象メソッドと同じである必要があります。
Javascript では、抽象メソッドというのは特にありません。
そこで、呼び出されたらエラーメッセージを表示するメソッドを作成します。ただし、エラーメッセージを表示するといっても普通のメソッドですから、必ずオーバーライドしなければならないということはありません。
Perl では、抽象メソッドというのは特にありません。
そこで、呼び出されたらエラーメッセージを表示するメソッドを作成します。ただし、エラーメッセージを表示するといっても普通のメソッドですから、必ずオーバーライドしなければならないということはありません。
Ruby では、抽象メソッドというのは特にありません。
そこで、呼び出されたらエラーメッセージを表示するメソッドを作成します。ただし、エラーメッセージを表示するといっても普通のメソッドですから、必ずオーバーライドしなければならないということはありません。
Python では、言語仕様としては抽象メソッドというのは特にありませんが、abcモジュールを使うことで抽象クラス・抽象メソッドを作成することができます。
抽象クラスは、abc.ABCMeta をインポートし、抽象メソッドには @abstractmethod デコレータを指定します。
抽象メソッドは修飾子 abstract で宣言します。
通常のメソッドならば、実際の処理が { } の中に記述されているはずですが、抽象メソッドの場合はセミコロン ; になっています。抽象メソッドでは、メソッド名と引数、戻り値の型の宣言だけ行います。
抽象メソッドは、実際の処理を記述せず、その入出力だけ宣言したメソッドとも言えます。インスタンス化するには継承して、抽象メソッドをオーバーライドして実装する必要があります。
抽象メソッドは修飾子 abstract で宣言します。
通常のメソッドならば、実際の処理が { } の中に記述されているはずですが、抽象メソッドの場合はセミコロン ; になっています。抽象メソッドでは、メソッド名と引数、戻り値の型の宣言だけ行います。
抽象メソッドは、実際の処理を記述せず、その入出力だけ宣言したメソッドとも言えます。インスタンス化するには継承して、抽象メソッドをオーバーライドして実装する必要がありますが、そのときシグネチャ(引数とそのデータ型の組)と戻り値型は抽象メソッドと同じである必要があります。
Swift では、抽象メソッドというのは特にありません。
そこで、呼び出されたらエラーメッセージを表示するメソッドを作成します。ただし、エラーメッセージを表示するといっても普通のメソッドですから、必ずオーバーライドしなければならないということはありません。
抽象メソッドは修飾子 abstract で宣言します。
通常のメソッドならば、実際の処理が { } の中に記述されているはずですが、抽象メソッドの場合はセミコロン ; になっています。抽象メソッドでは、メソッド名と引数、戻り値の型の宣言だけ行います。
抽象メソッドは、実際の処理を記述せず、その入出力だけ宣言したメソッドとも言えます。インスタンス化するには継承して、抽象メソッドをオーバーライドして実装する必要がありますが、そのときシグネチャ(引数とそのデータ型の組)と戻り値型は抽象メソッドと同じである必要があります。
Scala では、抽象メソッドとして宣言するための修飾子はありません。
通常のメソッドならば、実際の処理が { } の中に記述されているはずですが、抽象メソッドの場合はそれがありません。抽象メソッドでは、メソッド名と引数、戻り値の型の宣言だけ行います。
抽象メソッドは、実際の処理を記述せず、その入出力だけ宣言したメソッドとも言えます。インスタンス化するには継承して、抽象メソッドをオーバーライドして実装する必要がありますが、そのときシグネチャ(引数とそのデータ型の組)と戻り値型は抽象メソッドと同じである必要があります。
抽象メソッドは修飾子 abstract で宣言します。
通常のメソッドならば、実際の処理が { } の中に記述されているはずですが、抽象メソッドの場合はそれがありません。抽象メソッドでは、メソッド名と引数、戻り値の型の宣言だけ行います。
抽象メソッドは、実際の処理を記述せず、その入出力だけ宣言したメソッドとも言えます。インスタンス化するには継承して、抽象メソッドをオーバーライドして実装する必要がありますが、そのときシグネチャ(引数とそのデータ型の組)と戻り値型は抽象メソッドと同じである必要があります。
Go では、抽象メソッドというのは特にありません。
そこで、呼び出されたらエラーメッセージを表示するメソッドを作成します。ただし、エラーメッセージを表示するといっても普通のメソッドですから、必ずオーバーライドしなければならないということはありません。
抽象メソッドは修飾子 abstract で宣言します。
通常のメソッドならば、実際の処理が { } の中に記述されているはずですが、抽象メソッドの場合はセミコロン ; になっています。 抽象メソッドでは、メソッド名と引数、戻り値の型の宣言だけ行います。
抽象メソッドは、実際の処理を記述せず、その入出力だけ宣言したメソッドとも言えます。インスタンス化するには継承して、抽象メソッドをオーバーライドして実装する必要がありますが、そのときシグネチャ(引数とそのデータ型の組)と戻り値型は抽象メソッドと同じである必要があります。
抽象メソッドは修飾子 virtual と abstract を付け加えます。
procedure <メソッド名>([<引数>[, ...]]); virtual; abstract;
通常のメソッドならば、実際の処理が begin end の中に記述されているはずですが、抽象メソッドの場合はそれがありません。 抽象メソッドでは、メソッド名と引数、戻り値の型の宣言だけ行います。
抽象メソッドは、実際の処理を記述せず、その入出力だけ宣言したメソッドとも言えます。インスタンス化するには継承して、抽象メソッドをオーバーライドして実装する必要がありますが、そのときシグネチャ(引数とそのデータ型の組)と戻り値型は抽象メソッドと同じである必要があります。
(2)抽象クラス
抽象メソッドを持つクラスは抽象クラスであり、修飾子で abstract 宣言しておかなければなりません。
純粋仮想関数を持つクラスは抽象クラスです。
抽象メソッドを持つクラスは抽象クラスであり、修飾子で abstract 宣言しておかなければなりません。
抽象メソッドを持つクラスは抽象クラスであり、修飾子で MustInherit 宣言しておかなければなりません。
Javascript では、抽象クラスというのは特にありません。
そこで、呼び出されたらエラーメッセージを表示するメソッドをもつクラスとして作成します。ただし、インスタンス化はできてしまいます。
Perl では、抽象クラスというのは特にありません。
そこで、呼び出されたらエラーメッセージを表示するメソッドをもつクラスとして作成します。ただし、インスタンス化はできてしまいます。
Ruby では、抽象クラスというのは特にありません。
そこで、呼び出されたらエラーメッセージを表示するメソッドをもつクラスとして作成します。ただし、インスタンス化はできてしまいます。
抽象メソッドを持つクラスは抽象クラスであり、ABCMetaクラスを使用します。
抽象メソッドを持つクラスは抽象クラスであり、修飾子で abstract 宣言しておかなければなりません。
抽象メソッドを持つクラスは抽象クラスであり、修飾子で abstract 宣言しておかなければなりません。
Swift では、抽象クラスというのは特にありません。
そこで、呼び出されたらエラーメッセージを表示するメソッドをもつクラスとして作成します。ただし、インスタンス化はできてしまいます。
抽象メソッドを持つクラスは抽象クラスであり、修飾子で abstract 宣言しておかなければなりません。
抽象メソッドを持つクラスは抽象クラスであり、修飾子で abstract 宣言しておかなければなりません。
抽象メソッドを持つクラスは抽象クラスであり、修飾子で abstract 宣言しておかなければなりません。
Go では、抽象クラスというのは特にありません。
そこで、呼び出されたらエラーメッセージを表示するメソッドをもつクラスとして作成します。ただし、インスタンス化はできてしまいます。
抽象メソッドを持つクラスは抽象クラスであり、修飾子で abstract 宣言しておかなければなりません。
抽象メソッドを持つクラスは抽象クラスです。特に修飾子で abstract 宣言する必要はありません。
抽象クラスを利用するときには、抽象メソッドをオーバーライドし、処理内容を記述した派生クラスをインスタンス化する必要があります。しかし、抽象メソッドを一つでも持つクラスはインスタンス化できません。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、abstract を記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスには work メソッドを記述しなければならなくなります。よって、今度は work メソッドを記述していない Ambulance クラスがエラーになってしまいます。
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、= 0 を記述して、Car クラスを抽象クラスにしてみます。Car.cpp に work の記述はいりません。
抽象クラスの例
しかし、Car クラスの work メソッドを純粋仮想関数にすると、Car クラスを継承したすべての派生クラスには work メソッドを記述しなければならなくなります。よって、今度は work メソッドを記述していない Ambulance のインスタンスを生成するところでエラーになってしまいます。
そこで、Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの Work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような Work メソッドの処理は要りませんし、さらにいえば、Car クラスの Work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに Work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに Work メソッドを記述させるためにも、Car クラスの Work メソッドは抽象メソッドにすべきものなのでした。
それでは、abstract を記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの Work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスには Work メソッドを記述しなければならなくなります。よって、今度は Work メソッドを記述していない Ambulance クラスがエラーになってしまいます。
Ambulance クラスがエラーにならないようにするために、Work メソッドを記述します。
このように、Car クラスの Work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに Work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの Work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような Work メソッドの処理は要りませんし、さらにいえば、Car クラスの Work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに Work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに Work メソッドを記述させるためにも、Car クラスの Work メソッドは抽象メソッドにすべきものなのでした。
それでは、MustOverride や MustInherit を記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの Work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスには Work メソッドを記述しなければならなくなります。よって、今度は Work メソッドを記述していない Ambulance クラスがエラーになってしまいます。
Ambulance クラスがエラーにならないようにするために、Work メソッドを記述します。
このように、Car クラスの Work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに Work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、Car クラスを抽象クラス(work メソッドをオーバーライドしないで呼び出すとエラーメッセージが表示されるようなクラス)にしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスは work メソッドを記述しなければエラーメッセージが表示されるようになります。
実行結果です。
エラー:work メソッドを定義する必要があります。
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、Car クラスを抽象クラス(work メソッドをオーバーライドしないで呼び出すとエラーメッセージが表示されるようなクラス)にしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスは work メソッドを記述しなければエラーメッセージが表示されるようになります。
実行結果です。
エラー:work メソッドを定義する必要があります。
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、Car クラスを抽象クラス(work メソッドをオーバーライドしないで呼び出すとエラーメッセージが表示されるようなクラス)にしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスは work メソッドを記述しなければエラーメッセージが表示されるようになります。
実行結果です。
エラー:work メソッドを定義する必要があります。
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、@abstractmethod などを記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスには work メソッドを記述しなければならなくなります。よって、今度は work メソッドを記述していない Ambulance クラスがインスタンス生成時にエラーになってしまいます。
実行結果です。
amb = Ambulance()
TypeError: Can't instantiate abstract class Ambulance with abstract methods work
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、abstract を記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスは work メソッドを記述しなければエラーメッセージが表示されるようになります。
実行結果です(Ambulance クラスに抽象メソッドが残っているというエラーになっています)。
Fatal error: Class Ambulance contains 1 abstract method and must therefore be declared abstract
or implement the remaining methods (Car::work) in Ambulance/php
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、abstract を記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスには work メソッドを記述しなければならなくなります。よって、今度は work メソッドを記述していない Ambulance クラスがエラーになってしまいます。
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、Car クラスを抽象クラス(work メソッドをオーバーライドしないで呼び出すとエラーメッセージが表示されるようなクラス)にしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスは work メソッドを記述しなければエラーメッセージが表示されるようになります。
実行結果です。
Fatal error: エラー:work メソッドを定義する必要があります。
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、abstract を記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスには work メソッドを記述しなければならなくなります。よって、今度は work メソッドを記述していない Ambulance クラスがエラーになってしまいます。
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、abstract を記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスには work メソッドを記述しなければならなくなります。よって、今度は work メソッドを記述していない Ambulance クラスがエラーになってしまいます。
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、abstract を記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスには work メソッドを記述しなければならなくなります。よって、今度は work メソッドを記述していない Ambulance クラスがエラーになってしまいます。
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの Work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような Work メソッドの処理は要りませんし、さらにいえば、Car クラスの Work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに Work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに Work メソッドを記述させるためにも、Car クラスの Work メソッドは抽象メソッドにすべきものなのでした。
それでは、Car クラスを抽象クラス(Work メソッドをオーバーライドしないで呼び出すとエラーメッセージが表示されるようなクラス)にしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスは Work メソッドを記述しなければエラーメッセージが表示されるようになります。
実行結果です。
エラー:Work メソッドを定義する必要があります。
Ambulance クラスがエラーにならないようにするために、Work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、abstract を記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスは Work メソッドを記述しなければエラーメッセージが表示されるようになります。
実行結果です。work メソッドが記述されていないため、Ambulance クラスも抽象クラスと見なされ、インスタンスを生成できないというエラーになっています。
main.d(xx): Error: cannot create instance of abstract class `Ambulance` main.d(xx): function `void work()` is not implemented
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
抽象クラスは共通の機能を表現し、個々が持つ独自の機能はそれぞれの派生クラスで実装したい場合に使用します。例えば、今まで見てきました Car クラスの work メソッドは「何もしない」処理が書かれていました。
しかし、自動車の種類によって必ず処理が異なるならば、規定値のような work メソッドの処理は要りませんし、さらにいえば、Car クラスの work メソッドに処理が書かれていることによって、Car クラスを継承した派生クラスに work メソッドを記述し忘れても問題ないことになってしまいます。
したがって、各派生クラスに work メソッドを記述させるためにも、Car クラスの work メソッドは抽象メソッドにすべきものなのでした。
それでは、abstract を記述して、Car クラスを抽象クラスにしてみます。
抽象クラスの例
しかし、Car クラスの work メソッドを抽象メソッドにすると、Car クラスを継承したすべての派生クラスには work メソッドを記述しなければならなくなります。よって、今度は work メソッドを記述していない Ambulance クラスがエラーになってしまいます。
実行結果です。work メソッドが記述されていないため、Ambulance クラスも抽象クラスと見なされ、インスタンスを生成できないというエラーになっています。
[dcc32 警告] Main.dpr(14): W1020 クラス 'Ambulance' のインスタンスを作成していますが、このクラスは抽象メソッド 'Car.work' を含みます
Ambulance クラスがエラーにならないようにするために、work メソッドを記述します。
このように、Car クラスの work メソッドを抽象メソッドとして定義することによって、すべての派生クラスに work メソッドを記述させることができるようになります。
2 ポリモーフィズムと抽象クラス
基底クラスに抽象メソッドを作成しておくべきであるという理由として、各派生クラスに共通のメソッドを記述させるためとしましたが、この他にもうひとつ理由があります。
「基底クラス」型の変数に、「派生クラス」型のオブジェクトを代入することで、メソッドの働きが変わることをポリモーフィズムと呼びました。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、「基底クラス」型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。各派生クラスに共通のメソッドがあったとしても、基底クラスになければポリモーフィズムはできません。よって、そのために基底クラスに抽象メソッドを作成しておくわけです。
たとえば、基底クラスの Car クラスに存在しない siren メソッドを Car 型の変数で car.siren() と呼び出してみても、コンパイルエラーとなってしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。各派生クラスに共通のメソッドがあったとしても、基底クラスになければポリモーフィズムはできません。よって、そのために基底クラスに抽象メソッドを作成しておくわけです。
たとえば、基底クラスの Car クラスに存在しない siren メソッドを Car 型の変数で car->siren() と呼び出してみても、コンパイルエラーとなってしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように Work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの Work メソッドが呼び出されることです。
ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。各派生クラスに共通のメソッドがあったとしても、基底クラスになければポリモーフィズムはできません。よって、そのために基底クラスに抽象メソッドを作成しておくわけです。
たとえば、基底クラスの Car クラスに存在しない Siren メソッドを Car 型の変数で car.Siren() と呼び出してみても、コンパイルエラーとなってしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように Work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの Work メソッドが呼び出されることです。
ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。各派生クラスに共通のメソッドがあったとしても、基底クラスになければポリモーフィズムはできません。よって、そのために基底クラスに抽象メソッドを作成しておくわけです。
たとえば、基底クラスの Car クラスに存在しない Siren メソッドを Car 型の変数で car.Siren() と呼び出してみても、コンパイルエラーとなってしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
したがって、ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。しかし、Javascript の変数には型がありませんので、継承関係のないどのようなクラス間でも、基底クラスにそのメソッドがなくても、ポリモーフィズムすることができてしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
したがって、ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。しかし、Perl の変数には型がありませんので、継承関係のないどのようなクラス間でも、基底クラスにそのメソッドがなくても、ポリモーフィズムすることができてしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
したがって、ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。しかし、Ruby の変数には型がありませんので、継承関係のないどのようなクラス間でも、基底クラスにそのメソッドがなくても、ポリモーフィズムすることができてしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
したがって、ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。しかし、Python の変数には型がありませんので、継承関係のないどのようなクラス間でも、基底クラスにそのメソッドがなくても、ポリモーフィズムすることができてしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
したがって、ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。しかし、PHP の変数には型がありませんので、継承関係のないどのようなクラス間でも、基底クラスにそのメソッドがなくても、ポリモーフィズムすることができてしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。各派生クラスに共通のメソッドがあったとしても、基底クラスになければポリモーフィズムはできません。よって、そのために基底クラスに抽象メソッドを作成しておくわけです。
たとえば、基底クラスの Car クラスに存在しない siren メソッドを Car 型の変数で car.siren() と呼び出してみても、コンパイルエラーとなってしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。各派生クラスに共通のメソッドがあったとしても、基底クラスになければポリモーフィズムはできません。よって、そのために基底クラスに抽象メソッドを作成しておくわけです。
たとえば、基底クラスの Car クラスに存在しない siren メソッドを Car 型の変数で car.siren() と呼び出してみても、コンパイルエラーとなってしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。各派生クラスに共通のメソッドがあったとしても、基底クラスになければポリモーフィズムはできません。よって、そのために基底クラスに抽象メソッドを作成しておくわけです。
たとえば、基底クラスの Car クラスに存在しない siren メソッドを Car 型の変数で car.siren() と呼び出してみても、コンパイルエラーとなってしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、基底クラス型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。各派生クラスに共通のメソッドがあったとしても、基底クラスになければポリモーフィズムはできません。よって、そのために基底クラスに抽象メソッドを作成しておくわけです。
たとえば、基底クラスの Car クラスに存在しない siren メソッドを Car 型の変数で car.siren() と呼び出してみても、コンパイルエラーとなってしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、「基底クラス」型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
したがって、ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。しかし、Groovy では基底クラスにそのメソッドがなくても、ポリモーフィズムすることができてしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように Work メソッドを呼び出しても、インタフェース型の変数に代入されている派生クラスの Work メソッドが呼び出されることです。
したがって、ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、インタフェースにも記述する必要があります。
たとえば、基底クラスの Car クラスに存在しない Siren メソッドを ICar インタフェース型の変数で car.Siren() と呼び出してみても、コンパイルエラーとなってしまいます。
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、「基底クラス」型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。各派生クラスに共通のメソッドがあったとしても、基底クラスになければポリモーフィズムはできません。よって、そのために基底クラスに抽象メソッドを作成しておくわけです。
たとえば、基底クラスの Car クラスに存在しない siren メソッドを Car 型の変数で car.siren() と呼び出してみても、実行時にエラーとなってしまいます。
Car クラスに siren メソッドがないので、エラーになっています。
main.d(xx): Error: no property `siren` for type `Car.Car`
ポリモーフィズムの例
ポリモーフィズムとは、「基底クラス」型の変数を利用して同じように work メソッドを呼び出しても、「基底クラス」型の変数に代入されている派生クラスの work メソッドが呼び出されることです。
ポリモーフィズムを行うためには、各派生クラスに共通のメソッドがあることは当然ですが、基底クラスにも記述する必要があります。各派生クラスに共通のメソッドがあったとしても、基底クラスになければポリモーフィズムはできません。よって、そのために基底クラスに抽象メソッドを作成しておくわけです。
たとえば、基底クラスの Car クラスに存在しない siren メソッドを Car 型の変数で car.siren() と呼び出してみても、コンパイルエラーとなってしまいます。
Java、C++、C#、VB などでは、派生クラス型のオブジェクトが基底クラス型変数に代入されたときには、基底クラスに存在しない、派生クラス独自に宣言して実装したメソッドは使えません。そうすると、ポリモーフィズムを考えた場合、派生クラスでは、基底クラスで宣言されたメソッド以外は記述しない方が望ましいことになります。一方、基底クラスで宣言されていないメソッドやフィールドを追加することも極めてオブジェクト指向的なことです。
つまり、継承/実装には相反する二つの側面があるのです。
- 基底クラス型に代入された派生クラス型のオブジェクトでは、基底クラスで宣言されたメソッド以外は利用できなくなります。
- 共通する処理は基底クラスで実装しておき、派生クラスで独自の機能を追加することで省力化/拡張性の向上が図れます。
何れを選ぶかは、適用する状況に依存するもので、デザインパターンの勉強、コーディング経験の積み上げによって習得されます。
3 インタフェース
インタフェースは、抽象メソッドのみを持つ抽象クラスだと考えることができます。インタフェースの定義は以下のようにして行います。クラスを継承する場合はひとつしか指定できませんが、インタフェースの場合は複数指定できます。継承が複数ある場合には ,(コンマ)で区切って記述します。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- フィールド(メンバ変数)は定数となり、必ず値が代入されなければならない。自動的に final public static になる
- static メソッドを持つことができない
- 宣言したメソッド・プロパティはすべて public abstract になる(public abstract を記述してはいけない)
- 1つのクラスが複数のインターフェースを実装(継承)できる
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
インタフェースを実装するには、extends ではなく implements で、次のように行います。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
C++にはインタフェースという機能が存在しません。しかし、純粋仮想関数と仮想デストラクタを定義したクラスをインタフェースとして活用することができます。
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- フィールド(メンバ変数)を持つことができない
- static メソッドを持つことができない
- 宣言したメソッド・プロパティはすべて public abstract になる(public abstract を記述してはいけない)
- 1つのクラスが複数のインターフェースを実装(継承)できる
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
インタフェースを実装するには、クラスを継承する場合と同じで、次のように行います。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、Siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、Siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの RedLight メソッドが呼び出されます。しかし、無いので EmergencyCar の RedLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの Siren メソッドが呼び出されます。Siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの RedLight メソッドが呼び出されます。しかし、無いので EmergencyCar の RedLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの Siren メソッドが呼び出されます。Siren メソッドが実行されます。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- フィールド(メンバ変数)を持つことができない
- Shared メソッドを持つことができない
- 宣言したメソッド・プロパティはすべて Public MustOverride になる(Public MustOverride を記述してはいけない)
- 1つのクラスが複数のインターフェースを実装(継承)できる
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
クラスを継承する場合は Inherits を使用しましたが、インタフェースを実装するには、Implements を使用し、次のように行います。また、オーバーライドする各メソッドごとにも Implements を記述する必要があります。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、Siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、Siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの RedLight メソッドが呼び出されます。しかし、無いので EmergencyCar の RedLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの Siren メソッドが呼び出されます。Siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの RedLight メソッドが呼び出されます。しかし、無いので EmergencyCar の RedLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの Siren メソッドが呼び出されます。Siren メソッドが実行されます。
Javascript には、インタフェースというのは特にありません。
そこで、インタフェースを抽象クラス(メソッドをオーバーライドしないで呼び出すとエラーメッセージが表示されるようなクラス)として作成します。
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
Javascript では、インタフェースと言っても実際にはクラスです。
しかし、Javascript は、単一継承しかできないので、「基底クラス」と「インタフェース(に見せかけたクラス)」の2つを継承することもできません。そこで、インターフェースである IEmergency を継承し、Car に移譲することにします。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドは IEmergency のメソッドを呼び出しますので、エラーが表示されます。そのため、EmergencyCar を継承したクラスで siren メソッドを実装する必要があります。もちろん、EmergencyCar の中で、処理の実態のあるメソッドとして定義してもかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても ポリモーフィズムを行うことができるようになります。
- 〈宣言/定義〉
- 多重継承できないので、Car に処理を委譲するようにします。
- 〈処理の流れ〉
- 変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
Perl には、インタフェースというのは特にありません。
そこで、インタフェースを抽象クラス(メソッドをオーバーライドしないで呼び出すとエラーメッセージが表示されるようなクラス)として作成します。
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
Perl では、インタフェースと言っても実際にはクラスです。
なお、Perl は、多重継承できますので、「基底クラス」と「インタフェース(に見せかけたクラス)」の2つを継承することにします。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドは IEmergency のメソッドを呼び出しますので、エラーが表示されます。そのため、EmergencyCar を継承したクラスで siren メソッドを実装する必要があります。もちろん、EmergencyCar の中で、処理の実態のあるメソッドとして定義してもかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても ポリモーフィズムを行うことができるようになります。
- 〈宣言/定義〉
- Car と IEmergency を多重継承します。
- 〈処理の流れ〉
- 変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
Ruby には、インタフェースというのは特にありません。
そこで、インタフェースを抽象クラス(メソッドをオーバーライドしないで呼び出すとエラーメッセージが表示されるようなクラス)として作成します。
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
Ruby では、インタフェースと言っても実際にはクラスです。
しかし、Ruby は、単一継承しかできないので、「基底クラス」と「インタフェース(に見せかけたクラス)」の2つを継承することもできません。そこで、インターフェースである IEmergency を継承し、Car に移譲することにします。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドは IEmergency のメソッドを呼び出しますので、エラーが表示されます。そのため、EmergencyCar を継承したクラスで siren メソッドを実装する必要があります。もちろん、EmergencyCar の中で、処理の実態のあるメソッドとして定義してもかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても ポリモーフィズムを行うことができるようになります。
- 〈宣言/定義〉
- 多重継承できないので、Car に処理を委譲するようにします。
- 〈処理の流れ〉
- 変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
Python には、インタフェースというのは特にありません。
そこで、インタフェースを抽象クラスとして作成します。
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
Python では、インタフェースと言っても実際にはクラスです。
しかし、Python は、多重継承ができるので、「基底クラス」と「インタフェース(に見せかけたクラス)」の2つを継承することにします。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドは @abstractmethod が記述されていますので、実行時にエラーが表示されます。そのため、EmergencyCar を継承したクラスで siren メソッドを実装する必要があります。もちろん、EmergencyCar の中で、処理の実態のあるメソッドとして定義してもかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても ポリモーフィズムを行うことができるようになります。
- 〈宣言/定義〉
- Car と IEmergency を多重継承します。
- 〈処理の流れ〉
- 変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- フィールド(メンバ変数)は定数となり、必ず値が代入されなければならない。自動的に public static になる
- static メソッドを持つことができない
- 宣言したメソッド・プロパティはすべて public abstract になる(public abstract を記述してはいけない)
- 1つのクラスが複数のインターフェースを実装(継承)できる
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
インタフェースを実装するには、extends ではなく implements で、次のように行います。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても ポリモーフィズムを行うことができるようになります。
- $emc を宣言し、Ambulance のオブジェクトを設定します。
- $emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- $emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、$emc に設定します。
- $emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- $emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- 宣言したメソッドはすべて public abstract になる(public abstract を記述してはいけない)
- 1つのクラスが複数のインターフェースを実装(継承)できる
- フィールド(メンバ変数)も定義できるが、初期値は与えられない
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
インタフェースを実装するには、extends ではなく implements で、次のように行います。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- protocol で宣言する
- アクセス記述子を記述してはいけない
- 1つのクラスが複数のインターフェースを実装(継承)できる
- フィールド(プロパティ)も定義でき、{get set}(読み書き可能)、{get}(読み込み専用)を指定できる
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
インタフェースを実装するには、クラスの継承と同じく : で、次のように行います。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- 宣言したメソッドはすべて public abstract になる(public abstract を記述してはいけない)
- 1つのクラスが複数のインターフェースを実装(継承)できる
- フィールド(メンバ変数)も定義できるが、初期値は与えられない
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- 宣言したメソッドはすべて public abstract になる(public abstract を記述してはいけない)
- 1つのクラスが複数のインターフェースを実装(継承)できる
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- フィールド(メンバ変数)は定数となり、必ず値が代入されなければならない。自動的に final public static になる
- static メソッドを持つことができない
- 宣言したメソッド・プロパティはすべて public abstract になる(public abstract を記述してはいけない)
- 1つのクラスが複数のインターフェースを実装(継承)できる
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
インタフェースを実装するには、extends ではなく implements で、次のように行います。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
インタフェースには以下に挙げるような特徴があります。
- メソッドとインタフェースを宣言できる
- 1つのクラスが複数のインタフェースを実装(継承)できる
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
インタフェースを実装するには、継承と同様に次のように行います。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、Siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、Siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの RedLight メソッドが呼び出されます。しかし、無いので EmergencyCar の RedLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの Siren メソッドが呼び出されます。Siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの RedLight メソッドが呼び出されます。しかし、無いので EmergencyCar の RedLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの Siren メソッドが呼び出されます。Siren メソッドが実行されます。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- フィールド(メンバ変数)は持つことができない
- static メソッドや final メソッド以外のメソッドはすべて抽象メソッドになる
- static メソッドや final メソッドはメソッドの処理を記述できる
- 1つのクラスが複数のインターフェースを実装(継承)できる
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
インタフェースを実装するには、次のように行います。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
抽象クラスとよく似ていますが、インタフェースには以下に挙げるような特徴があります。
- フィールド(メンバ変数)は記述できない
- 宣言したメソッドはすべて public abstract になる(public を記述してはいけない)
- 1つのクラスが複数のインターフェースを実装(継承)できる
インタフェースの例です。緊急車両が持つべきメソッドを定義しています。
インタフェースを実装するには、クラスの場合と同様で、次のように行います。
サイレンを鳴らす緊急車両クラス EmergencyCar を定義してみます。インタフェースを実装するクラスでは、インタフェースで定義されたすべてのメソッドを記述する必要があります。メソッドが不足しているとエラーとなりますので、インタフェースを利用することによって、メソッドの定義のし忘れがなくなります。この例では、siren メソッドを抽象メソッドとして定義していますが、処理の実態のあるメソッドとして定義してももちろんかまいません。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直してみます。
EmergencyCar クラスを継承して Ambulance クラスと FireEngine クラスを定義し直したことによって、siren メソッドについても IEmergency インタフェース型の変数を使用してポリモーフィズムを行うことができるようになります。もちろん EmergencyCar クラス型の変数を使用してもかまいませんが、オブジェクトにアクセスする際に、特定のクラスの型を使うよりも、インタフェースの型を使う方が、特定のクラスへの癒着がなくなり、より「疎」な結合 (疎結合) が実現できるようになります。
- IEmergency インタフェース型の変数 emc を宣言し、Ambulance のオブジェクトを設定します。
- emc 内に保持している Ambulance オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している Ambulance オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
- FireEngine のオブジェクトを生成し、IEmergency インタフェース型の変数 emc に設定します。
- emc 内に保持している FireEngine オブジェクトの redLight メソッドが呼び出されます。しかし、無いので EmergencyCar の redLight メソッドが実行されます。
- emc 内に保持している FireEngine オブジェクトの siren メソッドが呼び出されます。siren メソッドが実行されます。
実行結果です。
赤色灯点灯 ピーポーピーポー 赤色灯点灯 ウーーカンカンカン