delegatej

 

(via: http://dreamhead.blogbus.com/index_4.html)

缘起

在Java里,为了启动一个线程,我们要创建一个实现Runnable接口的类:

public class MyParallelComputer implements Runnable {
  pulbic void run() {
    ...
  }
}

new Thread(new MyRunner()).start();

再有,为了响应一个按钮的事件,我们要创建一个ActionListener接口的类:

button.add(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
    ...
  }
});

所有这些,其实,我们需要的并不是一个类,而是满足一定约定的调用接口,只是因为我们用的是Java,让我们别无选择。做同样的事情,对比其它程序设计语言:

  • 很多程序设计语言里有lambda,甚至连方法名都可以省掉
  • C#里有delegate,只要方法的入参和返回值兼容,方法名也不重要
  • 即便是C,用函数指针,也只限定了入参和返回值,方法名也不重要

对比来看,Java的实现有两点堪称多余,类型和方法名。

在面向对象设计中,继承一种非常强的关系。虽然在语法层面上,我们只是简单地extends或implements一个类型,但实际上,背后隐藏着好多概念,比如is-a,比如LSP,所以,继承关系必须让我们小心翼翼,确保继承真的是继承。

再来看方法名,从之前几种程序设计语言的对比来看,对于这个调用接口而言,我们真正关心的只是入参和返回值,而方法名并不是我们的重点,而且,在现代程序设计中,方法名扮演着文档的作用,而实现这样的调用接口,我们不得不遵循这个死板的名字。所以,现实中经常的做法是,有一个按照自己意图命名的方法,在这个死板的方法中调用。

好吧,说了Java实现诸多的问题,接下来自然是要解决这样的问题,一起看看我们的主角:delegatej。

起步走

delegatej是一个基于annotation实现的delegate。从前面的介绍里面,你已经知道delegatej要解决问题是什么了。下面我们就来看看,如何应用delegatej。

假设我们有一个要实现的接口

public interface Executable {
    String execute(String name);
}

既然是一个基于annotation的实现,我们自然要有一个annotation,它就是给方法做标记的:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Handle {
}

再来,我们有一个要实现Executable接口的方法:

public class Runner {
    @Handle
    public String hello(String name) {
        return "hello " + name;
    }
}

与实现接口不同的是,这里只是用annotation标记了方法,没有强硬的继承关系,方法名也与接口标记的完全不同,相同的只是入参和返回值而已。要把这样的方法对接到接口上,就是delegatej发挥作用的地方了:

  Executable executable = delegate(Handle.class).to(Executable.class).trait(new Runner());
  executable.execute("dreamhead"); // "hello dreamhead"

这段代码的意思很清楚,把Handle这个annotation标记的方法委托给(delegate to)Executable接口的实现,然后,用这个约定从一个对象(new Runner())压榨(trait)出对应的方法来。这样一来,我们就得到了一个Executable接口的实现,也就可以当做Executable来用了,执行这个方法时,就会调用到hello方法。

同样,那个启动线程的例子就可以稍微修改一下:

public class MyParallelComputer {
  @Parallel
  pulbic void compute() {
    ...
  }
}

Runnable runnable = delegate(Parallel.class).to(Runnable.class).trait(new MyParallelComputer());
new Thread(runnable).start();

至于那个响应按钮事件的例子,就留给你做练习了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值