Java利用接口实现回调


        在Java支持方法指针之前,Java接口不能提供一种实现回调的好方法。如果您习惯于传递在事件驱动编程模型中调用的函数指针,则您会喜欢本技巧。

  熟悉MS-Windows和X Window System事件驱动编程模型的开发人员,习惯于传递在某种事件发生时调用(即“回调”)的函数指针。Java的面向对象模型目前并不支持方法指针,这样似乎就不可能使用这种很好的机制。但我们并不是一点办法都没有!

  Java的接口支持提供了一种获得回调的等价功能的机制。其技巧就是:定义一个简单接口,并在该接口中声明我们要调用的方法。

  例如,假定我们希望在某个事件发生时得到通知。我们可以定义一个接口:

       public interface InterestingEvent{
// 这仅是一个常规方法。因此如果需要,
// 它可有返回值,也可接收参数。
public void interestingEvent ();
}


        这使得我们可以控制实现该接口的类的任何对象。因此,我们不必关心任何外部类型信息。与在将C++代码用于Motif时使用窗口小部件的数据域来容纳对象指针的难以控制的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接口,并将自身引用传递给事件通知程序。

<SPAN style="FONT-SIZE: 18px"><STRONG>public class CallMe implements InterestingEvent{
private EventNotifier en;

public CallMe (){
// 创建事件通知程序,并将自身引用传递给它。
en = new EventNotifier (this);
}

// 为事件定义实际的处理程序。
public void interestingEvent (){
// 噢!必定发生了感兴趣的事件!
// 执行某些操作 ...
}

//...
}
</STRONG></SPAN>

下面给出上述例子的完整实现:

/* 
 * 考虑这样一个应用:希望在某个事件发生时得到通知 
 */  
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();  
          
    }  
      



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值