[Java]インタフェース


インタフェース


インタフェースとは?


インタフェースは抽象クラスです.インタフェースは抽象クラスと同様に抽象メソッドを持つが、抽象レベルは抽象クラスよりも高いため、体幹を持つ通常のメソッドやメンバー変数をメンバーとして使用することはできない.
抽象クラスを미완성 설계도と呼ぶと,インタフェースは下図のみを描く기본 설계と呼ぶことができる.

インタフェースの利点

  • の開発時間を短縮できます.
  • は標準化可能である.
  • は関係のない階級に関係を築くことができる.
  • は独立してプログラミングすることができる.
  • ゲームの中の小分隊を等級として表現し、彼らの関係を継承階層として表現する.

    すべてのユニットの最高祖先はユニットクラスであり,ユニットの種類は地上ユニットと空中ユニットに分けられる.
    このとき、SCVの修復方法を定義してTankやDropshipなどの機械化ユニットを修復する機能を提供すると、次のようになります.
    void repair(Tank t){ // Tank를 수리한다 }
    void repair(Dropship d) { // Dropship을 수리한다 }
    したがって、リペア可能なユニットの数に応じて異なるバージョンのオーバーロード方法を定義する必要があります.これを回避するためには、パラメータタイプを共通の祖先として使用することが望ましいが、Dropshipは共通の祖先が異なるため、解決できない.
    さらにGroundUnitのサブクラスにはMarineのような非機械化クラスも含まれる可能性があるので不適切である.
    このように継承関係に共通点が見えない場合,インタフェースを用いて既存の継承体系を維持しながらこれらの機械会ユニットに共通点を付与することができる.
    Repailableインタフェースを定義し、このインタフェースを保守可能な機械化ユニットに実装します.
    interface Repairable() { }
    
    class SCV extends GroundUnit implements Repairable { ... }
    
    class Tank extends GroundUnit implements Repairable { ... }
    
    class Dropship extends AirUnit implements Repairable { ... }
    リピート可能なインタフェースが実装されている場合、
  • デバイスごとにオーバーロード方法を定義する必要はありません.
  • 置換可能なタイプのパラメータを宣言します.
  • 以降に修復が必要な新しいクラスを作成すれば、新しいメソッドを定義することなくインタフェースを実現できます.
  • void repair (Repairable r) {
    	...
    }

    インタフェースの作成


    作成インタフェースは、クラスの作成と同じですが、クラスではなくinterfaceをキーワードとして使用するのと同じではありません.
    interface 인터페이스이름 {
    	public static final {타입} {상수이름} =;
    	public abstract {메서드이름}();
    }
    インタフェースのメンバーには、次の制限があります.
  • すべてのメンバー変数はpublic static finalでなければなりません.省略できます.
  • すべての方法は共通の要約でなければならず、省略することができる.(静的メソッドとエラーメソッドを除く(JDK 1.8から)
  • これはインタフェースで定義されたすべてのメンバーに適用される事項であるため省略可能であり,便宜上省略する場合が多い.スキップされたコントロールは、コンパイラによってコンパイル時に自動的に追加されます.

    インタフェースの継承


    インタフェースはインタフェースからのみ継承でき、クラスとは異なり、複数のインタフェースを継承できます.
    interface Movable {
    	void move(int x, int y);
    }
    
    interface Attackable {
    	void attack(Unit u);
    }
    
    interface Fightable extends Movable, Attackable { }
    Fightable自体はメンバーを定義していませんが、祖先インタフェースから継承された2つの抽象メソッドをメンバーとして所有します.

    インタフェースの実装

    class 클래스이름 implements 인터페이스이름 {
    }
    
    class Fighter implements Fightable {
    	public void move(int x, int y) { }
    	public void attack(Unit u) { }
    }
    実装されたインタフェースの一部のメソッドのみを実装する場合は、abstractを貼り付け、抽象クラスとして宣言する必要があります.
    abstract class Fighter implements Fightable {
    	public void move(int x, int y) { }
    }

    インタフェースを使用したマルチステート


    インタフェースは静的定数しか定義できないため、祖先クラスのメンバー変数と競合することは少なく、競合してもクラス名で区別できるため、インタフェースの多重継承を許可します.
    例えば、TvクラスとVCRクラスがある場合、TVRクラスを作成するためには、2つのクラスから継承することができず、1つのクラス継承しか選択できず、もう1つのクラスがクラスに含まれ、内部生成インスタンス使用のために使用される.
    public class TV {
    	protected boolean power;
    	protected int channel;
    	protected int volume;
    
    	public void power() { power!=power; }
    	public void channelUp() { channel++; }
    	public void channelDown() { channel--; }
    	public void volumeUp() { volume++; }
    	public void volumeDown() { volume--; }
    }
    
    public class VCR {
    	protected int counter;
    
    	public void play() {
    	}
    	public void stop() {
    	}
    	public void reset() {
    		counter = 0;
    	}
    	public int getCounter() {
    		return counter;	
    	}
    	public void setCounter(int c) {
    		counter = c;
    	}
    }
    /* VCR에 대한 인터페이스 IVCR */
    public interface IVCR {
    	public void play();
    	public void stop();
    	public void reset();
    	public int getCounter();
    	public void setCounter(int c);
    }
    IVCRインタフェースが実装され、Tvクラスから継承されたTVCRクラスが作成されます.
    public class TVCR extends Tv implements IVCR {
    	VCR vcr = new VCR();
    
    	public void play() {
    		vcr.play();
    	}
    	public void stop() {
    		vcr.stop();
    	}
    	public void reset() {
    		vcr.reset();
    	}
    	public int getCounter() {
    		return vcr.getCounter();
    	}
    	public void setCounter(int c) {
    		vcr.setCounter(c);
    	}
    }
    実際,インタフェースを書き直す必要はなく,VCRクラスをTVCクラスに含めるだけで十分であるが,インタフェースを利用する利点は,その多方面の特性を利用できることである.

    インタフェースを使用したマルチフォーム化


    インタフェースは、そのクラスを実装する祖先と呼ぶことができるので、インタフェースタイプの参照変数参照を使用してそのクラスインスタンスを実装することができます.
    Fightable f = (Fightable)new Fighter();
    Fightable f = new Fighter();
    メソッドの戻りタイプを使用して、インタフェースのタイプを指定できます.
    Fightable method() {
    	...
    	Fighter f = new Fighter();
    	return f;
    }
    Returnタイプはインタフェースであり、これはメソッドがインタフェースを実装するクラスのインスタンスを返すことを意味する.

    インタフェースの理解


    これまで,インタフェースの特徴,実現方法,利点などを理解してきた.しかし「インタフェースはいったい何ですか?」このような疑問は依然として存在する.今回はインタフェースの本質を見てみましょう.
    まず,インタフェースを理解するためには,以下の2つの事項を考慮しなければならない.
  • クラスを使用するユーザと提供クラスのプロバイダがある.
  • メソッドを使用するユーザは、使用するメソッドの宣言子を知るだけでよい.△内容は知らなくてもいいです.
  • class A {
    	public void methodA (B b) {
    		b.methodB();
    	}
    }
    
    class B {
    	public void methodB() {
    		System.out.println("methodB()");
    	}
    }
    前述したように、A,Bが存在する場合、互いに直接関係がある.(A-B関係)
    この場合、Aクラスを記述するためには、Bクラスが完了している必要があり、BクラスのメソッドB()の宣言部分が変更された場合、A部分のコードを変更する必要がある.
    この場合,インタフェースを媒介としてAクラスをインタフェースを介してBクラスにアクセスさせる方法では,Bクラスが変更されてもAクラスは何ら影響を受けない.
    interface I {
    	public abstract void methodB();
    }
    
    class B implements I {
    	public void methodB() {
    		System.out.println("methodB in B class");
    	}
    }
    
    class A {
    	public void methodA (I i) {
    		i.methodB();
    	}
    }
    Aクラスは依然としてBクラスのメソッドを呼び出すが、それらの関係は「A-B」ではなく「A-I」であるため、Bクラスの変更の影響を受けない.したがって,クラスAはインタフェースを介して実際に使用されるクラスの名前を知る必要はなく,実際に実装されるクラスさえ必要としない.
    class A{
    	void autoPlay(I i) {
    		i.play();
    	}
    }
    
    interface I {
    	public abstract void play();
    }
    
    class B implements I {
    	public void play() {
    		System.out.println("play in B class");
    	}
    }
    
    class C implements I {
    	public void play() {
    		System.out.println("play in C class");
    	}
    }
    
    class InterfaceTest {
    	public static void main(String[] args) {
    		A a = new A();
    		A.autoPlay(new B());
    		A.autoPlay(new C());
    	}
     }
    /* 실행결과 */
    // play in B class
    // play in C class
    AクラスはインタフェースIを用いて記述されるが、パラメータによってインタフェースIを実装するクラスのインスタンスを動的に提供する必要がある.
    クラスThreadの作成者Thread(Runnable target)はこのような方法です.
    (Runnableこのインタフェース)
    このようなパラメータによって動的に提供される方法に加えて、第3のクラスによって提供することもできる.JDBCのDriveManagerクラスはこうです.
    class InterfaceTest {
    	public static void main(String[] args){
    		A a = new A();
    		a.methodA();
    	}
    }
    
    class A{
    	void methodA() {
    		I i = InstanceManager.getInstance();
    		i.methodB();
    		System.out.println(i.toString()); // 모든 객체는 Object클래스에 정의된 메서드를 가지고 있기에 사용 가능
    	}
    }
    
    interface I {
    	public abstract void methodB();
    }
    
    class B implements I {
    	public void methodB() {
    		System.out.println("play in B class");
    	}
    	public String toString() {return "class B";}
    }
    
    class InstanceManager {
    	public static I getInstance() {
    		return new B();
    	}
    }
    インスタンスを直接生成するのではなく、getInstance()メソッドで提供します.このような利点は、後で他のクラスのインスタンスに変更する場合、getInstance()を変更するだけでAクラスを変更しないことです.