Javaインタフェースによるコールバック


Javaがメソッドポインタをサポートするまで、Javaインタフェースはコールバックを実現する良い方法を提供できません.このテクニックは、イベント駆動プログラミングモデルで呼び出された関数ポインタを渡すのに慣れている場合に便利です. MS-WindowsとX Window Systemイベント駆動プログラミングモデルを熟知している開発者は、あるイベントが発生したときに呼び出される(すなわち「コールバック」)関数ポインタを渡すことに慣れています.Javaのオブジェクト向けモデルは現在メソッドポインタをサポートしていないため,このような良いメカニズムを使用することは不可能であるようだ.しかし、私たちは少しも方法がないわけではありません. Javaのインタフェースサポートは,コールバックの等価機能を得るメカニズムを提供する.そのテクニックは、単純なインタフェースを定義し、呼び出す方法を宣言することです. 
たとえば、あるイベントが発生したときに通知されることを望んでいるとします.インタフェースを定義できます. 
public interface InterestingEvent{ 
//          。      , 
//       ,      。 
public void interestingEvent (); 
} 

これにより、インタフェースを実装するクラスの任意のオブジェクトを制御することができます.したがって、外部タイプの情報に関心を持つ必要はありません.この方法は,MotifにC++コードを用いる場合にウィンドウウィジェットのデータドメインを用いてオブジェクトポインタの制御が困難なC関数を格納するよりもはるかに優れている. イベント信号を送信するクラスは、InterestingEventインタフェースが実装されたオブジェクトを待機し、適切なタイミングでinterestingEvent()メソッドを呼び出す必要があります. 
public class EventNotifier{ 
private InterestingEvent ie; 
private boolean somethingHappened; 

public EventNotifier (InterestingEvent event){ 
//           。 
ie = event; 

//          。 
somethingHappened = false; 
} 

//... 

public void doWork (){ 
//           。 
if (somethingHappened){ 
//                  。 
ie.interestingEvent (); 
} 
//... 
} 

// ... 
} 

前の例では、somethingHappened述語を使用して、イベントをトリガーすべきかどうかを追跡しました.多くの場合、この方法を呼び出すと、interestingEvent()への信号の送信を保証するのに十分である. イベント通知を受信するコードは、InterestingEventインタフェースを実装し、イベント通知プログラムに自身の参照を渡す必要があります. 
public class CallMe implements InterestingEvent{ private EventNotifier en; public CallMe (){ //         ,          。 en = new EventNotifier (this); } //             。 public void interestingEvent (){ //  !           ! //        ... } //... } 

以下に、上記の例の完全な実装を示す.
/* 
 *         :               
 */  
interface InterestingEvent {  
      
    public void interestingEvent();  
      
}  
  
  
class EventNotifier {  
      
    private InterestingEvent ie;        //  private List<InterestingEvent> eventList          
    private boolean somethingHappened;  
      
    public EventNotifier(InterestingEvent ie) {  
        this.ie = ie;  
        this.somethingHappened = false;  
    }  
      
    public void setHappened() {  
        this.somethingHappened = true;  
    }  
      
    public void doWork() {  
        if (somethingHappened) {  
            ie.interestingEvent();  
        }  
    }  
      
}  
  
  
class ButtonPressedEvent implements InterestingEvent {  
  
    @SuppressWarnings("unused")  
    private EventNotifier en;  
      
    public ButtonPressedEvent() {  
        en = new EventNotifier(this);  
    }  
      
    public void interestingEvent() {  
        System.out.println("button pressed ");  
    }  
      
}  
  
  
class EventNotifierTest {  
      
    public static void test() {  
        //         。            ,      “  Client  ”      
        EventNotifier en = new EventNotifier(new ButtonPressedEvent());  
        en.setHappened();  
        en.doWork();  
          
        EventNotifier en2 = new EventNotifier(new InterestingEvent(){  
            public void interestingEvent() {  
                System.out.println("inputtext change ");  
            }  
        });  
        en2.setHappened();  
        en2.doWork();  
          
    }  
}  
  
  
//           
public class JavaInterfaceCallBack {  
      
    public static void main(String[] args) {  
         
        ChangeNameTest.test();  
        EventNotifierTest.test();  
          
    }  
  
}  

コールバックのモデルと別の例を示して、より良い学習を実現します.
/* 
 * Java       ,           
 */  
interface A {}  
  
class B implements A {}  
  
class C implements A {}  
  
class Test {  
    A b = new B();  
    A c = new C();  
}  
/* 
 *         : NameChanger     Client    
 *  NameChanger changeName        Client  ,    (  )Client           
 * Client    NameChanger,            
 */  
class Client {  
  
    private INameChanger changer;  
    private String clientName;  
      
  
    public Client(INameChanger changer) {  
        this.changer = changer;  
    }  
  
    public void showMyNewName() {  
        String newName = changer.changeName(Client.this);  
        System.out.println(newName);  
    }  
      
    public String getName() {  
        return clientName;  
    }  
  
    public void setName(String clientName) {  
        this.clientName = clientName;  
    }  
}  
  
 interface INameChanger {  
      
    public String changeName(Client client);  
      
}  
  
  
public class ChangeNameTest {  
      
    public static void main(String[] args) {  
          
        Client client = new Client(new INameChanger(){  
            public String changeName(Client client) {  
                return "Mr." + client.getName();  
            }  
        });  
        client.setName("Tom");  
        client.showMyNewName();  
          
        Client client2 = new Client(new INameChanger(){  
            public String changeName(Client client) {  
                return "Miss." + client.getName();  
            }  
        });  
        client2.setName("Lucy");  
        client2.showMyNewName();  
          
    }  
      
}