コンテンツにスキップ

「インタフェース (抽象型)」の版間の差分

出典: フリー百科事典『ウィキペディア(Wikipedia)』
削除された内容 追加された内容
m編集の要約なし
タグ: モバイル編集 モバイルウェブ編集 改良版モバイル編集
Sycgln (会話 | 投稿記録)
(同じ利用者による、間の2版が非表示)
1行目: 1行目:
'''インタフェース''' ({{lang-en-short|interface}}) は、[[Java]]や[[C Sharp|C#]]などの[[オブジェクト指向プログラミング言語]]においてサポートされる、実装を持たない[[抽象型]]のことである。これらの言語において、[[クラス (コンピュータ)|クラス]]は実装の[[多重継承]]をサポートしない代わりに、任意の数のインタフェースを実装 (implement) することができ、これにより型の多重継承をサポートする。複数の種類の[[オブジェクト (プログラミング)|オブジェクト]]を、インタフェースを用いた[[多態性]]によって統一的に扱うことができるようになる。'''インターフェス'''などと表記することもある<ref>例えば[[オラクル (企業)|オラクル]]の日本語ドキュメントでは「インタフェース」と表記されているが、[[マイクロソフト]]の日本語ドキュメントでは「インターフェイス」と表記されている。本記事では「インタフェース」で統一するものとする。</ref>。
'''インタフェース''' ({{lang-en-short|Interface}}) '''インターフェス'''<ref>例えば[[オラクル (企業)|オラクル]]の日本語ドキュメントでは「インタフェース」と表記されているが、[[マイクロソフト]]の日本語ドキュメントでは「インターフェイス」と表記されている。本記事では「インタフェース」で統一するものとする。</ref>、主に[[オブジェクト指向プログラミング言語|オブジェクト指向言語]]で用いられている、実装と分離された[[抽象型]]の一種である。抽象化されたプログラムの動作・振る舞い(behavior)を扱うための手法である。[[統一モデリング言語|UML]][[クラス図]]の実現(realization)・実装(implementation)の関係に投影されたことで、OOPで重要視されるようになっている。より公式的にはプロトコル(Protocol)とも呼ばれ、それは[[関数型プログラミング|関数型]]のモジュールシグネチャ(signature)や[[手続き型プログラミング|手続き型]]のモジュール仕様書(specification)などを包括している

インターフェースの基本形は[[関数プロトタイプ|メソッドシグネチャ]]の集合体であり、概ね以下の項目で構成される。

# インターフェース名。{{仮リンク|記名的型付け|en|Nominal type system}}での識別を前提にしている。
# 「リターン型+メソッド名+パラメータリスト」の[[メソッド (計算機科学)|メソッド]]定義。メソッド実装([[コードブロック]])は除外される。
# 各メソッドからスローされる[[例外処理|例外クラス]]の宣言。
# 専用の[[定数 (プログラミング)|定数]]。

インターフェースの使用は[[Java]]や[[C Sharp|C#]]が有名であり、それらの言語では、メソッド実装=実装継承の[[多重継承]]をサポートしない代わりに、メソッド定義集合=純粋な界面継承の[[多重継承]]をサポートすることにしている。純粋な界面継承を表現する機能がインターフェースになった。インターフェース型の[[変数 (プログラミング)|変数]]には、その実装が宣言された各[[クラス (コンピュータ)|クラス]]の[[インスタンス]]が代入されて、どれが代入されるかは実行時に決定される。これは変数の[[サブタイピング]]の[[ポリモーフィズム]]になり、多様な[[オブジェクト (プログラミング)|オブジェクト]]を一つのインターフェースで扱える効用がある。


== 概要 ==
== 概要 ==
オブジェクト指向プログラミングにおいて、[[多重継承]]はプログラミングの自由度と柔軟性を向上する。[[C++]]は「実装の多重継承」をサポートし、クラスは複数の[[スーパークラス (計算機科学)|スーパークラス]](基底クラス)を持つことができる。しかし、実装の多重継承は[[菱形継承問題]]などの欠点を抱えている。実装の多重継承の問題点を回避するためにC++は[[仮想継承]]の仕組みを導入したが、これはプログラミング言語仕様が複雑化する原因となった。しかし、「型の多重継承」に限れば、問題点の多くは回避でき、また言語仕様もシンプルになる。JavaおよびC#では、実装の継承は単一継承に制限したうえで、代わりに具体的な実装を持たないインタフェースによる型の多重継承の仕組みを導入し、多重継承問題に対する解決策を提供している<ref>{{Cite web|url=https://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-JF18-Interfaces.pdf|title=進化するJavaインタフェース - Javaの多重継承を理解する -|author=Michael Kölling|accessdate=2019-02-24}}</ref>。
オブジェクト指向プログラミングにおいて、[[多重継承]]はプログラミングの自由度と柔軟性を向上する。[[C++]]は「実装の多重継承」をサポートし、クラスは複数の[[スーパークラス (計算機科学)|スーパークラス]](基底クラス)を持つことができる。しかし、実装の多重継承は[[菱形継承問題]]などの欠点を抱えている。実装の多重継承の問題点を回避するためにC++は[[仮想継承]]の仕組みを導入したが、これはプログラミング言語仕様が複雑化する原因となった。しかし、「型の多重継承」に限れば、問題点の多くは回避でき、また言語仕様もシンプルになる。JavaおよびC#では、実装の継承は単一継承に制限したうえで、代わりに具体的な実装を持たないインタフェースによる型の多重継承の仕組みを導入し、多重継承問題に対する解決策を提供している<ref>{{Cite web|url=https://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-JF18-Interfaces.pdf|title=進化するJavaインタフェース - Javaの多重継承を理解する -|author=Michael Kölling|accessdate=2019-02-24}}</ref>。


インタフェース自身はインスタンス化(実体化)することができないが、任意のクラスにてインタフェースを実装することで、そのクラスのインスタンスは当該インタフェースとして振る舞うことが可能となる[[リスコフの置換原則]]
インタフェース自身はインスタンス化(実体化)することができないが、任意のクラスにてインタフェースを実装することで、そのクラスのインスタンスは当該インタフェースとして振る舞うことが可能となる。これは[[リスコフの置換原則]]に忠実な[[継承 (プログラミング)|継承]]の用法である。これは純粋な界面継承と(interface inheritance)と言われる。UML[[クラス図]]では実装(implementation)の関係に投影されている。90年代OOPの原則セット[[GRASP]]では保護的変容(protected variations)に該当される

JavaおよびC#では、抽象[[メソッド (計算機科学)|メソッド]](実装を持たないメソッド宣言)を持ち、実体化できないクラス(抽象クラス)を定義することも可能であるが、抽象クラスは実装を持つことも可能であり、インタフェースと違って多重継承することはできない。こちらは界面継承と実装継承(implementation inheritance)の混合になる。UMLクラス図では特化(specification)の関係に投影されている。[[GRASP]]では多態性(polymorphism)に該当される


インターフェースは、2000年代OOPの原則セット[[SOLID]]で特に重視されるようになっている。[[依存性逆転の原則]]では、[[Mixin|Mix-in]]の作法をインターフェースの用法に適用しており、Mix-inでの[[トレイト]]の役割を持たせたインターフェースを、機能提供の依存対象としてクラスに結合(注入)するデザインパターンが提唱されている。GRASPはこれを純粋造形(pure fabrication)として予告提唱していた。その際のインターフェースは、[[ドメイン駆動設計]]のサービスに相当するものになる。
JavaおよびC#では、抽象[[メソッド (計算機科学)|メソッド]](実装を持たないメソッド宣言)を持ち、実体化できないクラス(抽象クラス)を定義することも可能であるが、抽象クラスは実装を持つことも可能であり、インタフェースと違って多重継承することはできない。


== Java ==
== Java ==
86行目: 97行目:
また、C#では<code>Guid</code>属性(<code>System.Runtime.InteropServices.GuidAttribute</code>クラス)により、インタフェースやクラスに[[GUID]]を付加することができる。[[.NET Framework]]のインタフェースやクラスを含む[[アセンブリ (共通言語基盤)|アセンブリ]]をCOMコンポーネントとして公開し、C++ネイティブコードや[[VBScript]]/[[JScript]]といった従来のCOM/[[Object Linking and Embedding|OLE]]対応言語などから利用するCOM相互運用も可能である<ref>[https://docs.microsoft.com/ja-jp/dotnet/framework/interop/exposing-dotnet-components-to-com COM への .NET Framework コンポーネントの公開 | Microsoft Docs]</ref>。
また、C#では<code>Guid</code>属性(<code>System.Runtime.InteropServices.GuidAttribute</code>クラス)により、インタフェースやクラスに[[GUID]]を付加することができる。[[.NET Framework]]のインタフェースやクラスを含む[[アセンブリ (共通言語基盤)|アセンブリ]]をCOMコンポーネントとして公開し、C++ネイティブコードや[[VBScript]]/[[JScript]]といった従来のCOM/[[Object Linking and Embedding|OLE]]対応言語などから利用するCOM相互運用も可能である<ref>[https://docs.microsoft.com/ja-jp/dotnet/framework/interop/exposing-dotnet-components-to-com COM への .NET Framework コンポーネントの公開 | Microsoft Docs]</ref>。


== その他言語・技術 ==
== その他言語とテクノロジ ==
C++ではpublicな純粋仮想関数および純粋仮想[[デストラクタ]]のみを持つクラス(あるいは[[構造体]])を定義することで、JavaやC#のインタフェースを模倣し、多重継承の欠点を回避することもできる。
C++ではpublicな純粋仮想関数および純粋仮想[[デストラクタ]]のみを持つクラス(あるいは[[構造体]])を定義することで、JavaやC#のインタフェースを模倣し、多重継承の欠点を回避することもできる。


96行目: 107行目:
== 関連項目 ==
== 関連項目 ==
* [[抽象型]]
* [[抽象型]]
* [[クラス (コンピュタ)]]
* [[ポリモフィズム]]
* [[継承 (プログラミング)]]
*[[サブタイピング]]
*[[継承 (プログラミング)|継承]]
* [[インタフェース (情報技術)]]
*[[クラス (コンピュータ)|クラス]]


{{デフォルトソート:いんたふえいす}}
{{デフォルトソート:いんたふえいす}}

2021年11月7日 (日) 01:53時点における版

インタフェース (: Interface) インターフェース[1]、主にオブジェクト指向言語で用いられている、実装と分離された抽象型の一種である。抽象化されたプログラムの動作・振る舞い(behavior)を扱うための手法である。UMLクラス図の実現(realization)・実装(implementation)の関係に投影されたことで、OOPで重要視されるようになっている。より公式的にはプロトコル(Protocol)とも呼ばれ、それは関数型のモジュールシグネチャ(signature)や手続き型のモジュール仕様書(specification)などを包括している。

インターフェースの基本形はメソッドシグネチャの集合体であり、概ね以下の項目で構成される。

  1. インターフェース名。記名的型付け英語版での識別を前提にしている。
  2. 「リターン型+メソッド名+パラメータリスト」のメソッド定義。メソッド実装(コードブロック)は除外される。
  3. 各メソッドからスローされる例外クラスの宣言。
  4. 専用の定数

インターフェースの使用はJavaC#が有名であり、それらの言語では、メソッド実装=実装継承の多重継承をサポートしない代わりに、メソッド定義集合=純粋な界面継承の多重継承をサポートすることにしている。純粋な界面継承を表現する機能がインターフェースになった。インターフェース型の変数には、その実装が宣言された各クラスインスタンスが代入されて、どれが代入されるかは実行時に決定される。これは変数のサブタイピングポリモーフィズムになり、多様なオブジェクトを一つのインターフェースで扱える効用がある。

概要

オブジェクト指向プログラミングにおいて、多重継承はプログラミングの自由度と柔軟性を向上する。C++は「実装の多重継承」をサポートし、クラスは複数のスーパークラス(基底クラス)を持つことができる。しかし、実装の多重継承は菱形継承問題などの欠点を抱えている。実装の多重継承の問題点を回避するためにC++は仮想継承の仕組みを導入したが、これはプログラミング言語仕様が複雑化する原因となった。しかし、「型の多重継承」に限れば、問題点の多くは回避でき、また言語仕様もシンプルになる。JavaおよびC#では、実装の継承は単一継承に制限したうえで、代わりに具体的な実装を持たないインタフェースによる型の多重継承の仕組みを導入し、多重継承問題に対する解決策を提供している[2]

インタフェース自身はインスタンス化(実体化)することができないが、任意のクラスにてインタフェースを実装することで、そのクラスのインスタンスは当該インタフェースとして振る舞うことが可能となる。これはリスコフの置換原則に忠実な継承の用法である。これは純粋な界面継承と(interface inheritance)と言われる。UMLクラス図では実装(implementation)の関係に投影されている。90年代OOPの原則セットGRASPでは保護的変容(protected variations)に該当される。

JavaおよびC#では、抽象メソッド(実装を持たないメソッド宣言)を持ち、実体化できないクラス(抽象クラス)を定義することも可能であるが、抽象クラスは実装を持つことも可能であり、インタフェースと違って多重継承することはできない。こちらは界面継承と実装継承(implementation inheritance)の混合になる。UMLクラス図では特化(specification)の関係に投影されている。GRASPでは多態性(polymorphism)に該当される。

インターフェースは、2000年代OOPの原則セットSOLIDで特に重視されるようになっている。依存性逆転の原則では、Mix-inの作法をインターフェースの用法に適用しており、Mix-inでのトレイトの役割を持たせたインターフェースを、機能提供の依存対象としてクラスに結合(注入)するデザインパターンが提唱されている。GRASPはこれを純粋造形(pure fabrication)として予告提唱していた。その際のインターフェースは、ドメイン駆動設計のサービスに相当するものになる。

Java

Javaのインタフェースは、暗黙的にpublicな抽象メソッドのみを持つことが許される参照型である。定数および入れ子になった型の定義は許される。Javaではクラスの継承にextendsキーワードを使用するが、インタフェースの実装にはimplementsキーワードを使用する。インタフェースを拡張して新たなインタフェースを派生させるときはextendsキーワードを使う。

// 「飛ぶ」ことができるもの全般を表すインタフェース。
interface Flyable {
    void fly();
}

// 動物の抽象基底クラス。
abstract class Animal {
}

// 鳥類の抽象基底クラス。空を飛べないダチョウやペンギンも含まれる。
abstract class Bird extends Animal {
}

// 飛べる鳥類の抽象基底クラス。
abstract class FlyingBird extends Bird implements Flyable {
}

// ワシの具象クラス。
class Eagle extends FlyingBird {
    @Override
    public void fly() { System.out.println("Eagle.fly()"); }
}

// 哺乳類の抽象基底クラス。
abstract class Mammal extends Animal {
}

// 飛べる哺乳類の抽象基底クラス。
abstract class FlyingMammal extends Mammal implements Flyable {
}

// コウモリの具象クラス。
class Bat extends FlyingMammal {
    @Override
    public void fly() { System.out.println("Bat.fly()"); }
}

// 航空機の抽象基底クラス。自力で航行できないグライダーも含まれる。
abstract class Aircraft {
}

// エンジンを搭載した飛行機の具象クラス。
class Airplane extends Aircraft implements Flyable {
    @Override
    public void fly() { System.out.println("Airplane.fly()"); }
}

public class Main {
    public static void main(String[] args) {
        final Flyable[] flyables = {
            new Eagle(),
            new Bat(),
            new Airplane(),
        };
        for (final Flyable obj : flyables) {
            obj.fly();
        }
    }
}

上記では、互いに異なる基底クラスを持つ派生クラス群であっても、Flyableインタフェースを導入することで一様に扱うことができる例を示している。

Javaの列挙型は抽象クラスjava.lang.Enumから暗黙的に派生する参照型であり、任意のインタフェースを実装することができる。

なお、Java 8以降ではインタフェースのデフォルトメソッドにより、実装の多重継承も限定的にサポートするようになった。また、インタフェースが静的メソッドを持つこともできるようになった[3]。Java 8で導入されたラムダ式およびメソッド参照は、実装すべきメソッドをひとつだけ持つ「関数型インタフェース」(functional interface) によって実現されている。

C#

C#のインタフェースは、概ねJava同様であり、暗黙的にpublicな抽象メソッド、抽象プロパティ、抽象インデクサのみを持つことが許される参照型である。ただし、定数および入れ子になった型の定義は許されない。インタフェース名はIで始めることが推奨されている。言語の機能や設計の観点から言うと、C#のインタフェースにはDelphi (Object Pascal) のインタフェースの影響が強く見られる。

C#の構造体は抽象クラスSystem.ValueTypeから暗黙的に派生する値型であり、基底クラスを明示的に指定することはできないが、任意のインタフェースを実装することはできる。C#の列挙型は抽象クラスSystem.Enumから暗黙的に派生する値型であるが、構造体とは違って任意のインタフェースを実装することはできない。構造体および列挙型のインスタンスは、実装されたインタフェース型の変数に暗黙的に代入できるが、型変換(キャスト)の際にボックス化が発生する。

usingステートメントで使用できるSystem.IDisposableのように、構文上特別扱いされるようになるインタフェース型もある。

また、C#ではGuid属性(System.Runtime.InteropServices.GuidAttributeクラス)により、インタフェースやクラスにGUIDを付加することができる。.NET Frameworkのインタフェースやクラスを含むアセンブリをCOMコンポーネントとして公開し、C++ネイティブコードやVBScript/JScriptといった従来のCOM/OLE対応言語などから利用するCOM相互運用も可能である[4]

その他言語とテクノロジ

C++ではpublicな純粋仮想関数および純粋仮想デストラクタのみを持つクラス(あるいは構造体)を定義することで、JavaやC#のインタフェースを模倣し、多重継承の欠点を回避することもできる。

マイクロソフトComponent Object Model (COM) は、プログラミング言語を問わず再利用可能なソフトウェアコンポーネントを作成するために用いられる技術であり、COMインタフェースはIUnknown派生の実装を持たない抽象型として、COMサーバーとCOMクライアントをつなぐ役割を果たす。COMの思想や概念はのちに.NET FrameworkWindowsランタイムにも受け継がれることになった。

脚注・出典

  1. ^ 例えばオラクルの日本語ドキュメントでは「インタフェース」と表記されているが、マイクロソフトの日本語ドキュメントでは「インターフェイス」と表記されている。本記事では「インタフェース」で統一するものとする。
  2. ^ Michael Kölling. “進化するJavaインタフェース - Javaの多重継承を理解する -”. 2019年2月24日閲覧。
  3. ^ Default Methods (The Java™ Tutorials > Learning the Java Language > Interfaces and Inheritance)
  4. ^ COM への .NET Framework コンポーネントの公開 | Microsoft Docs

関連項目