呃…… 标题不太好。让我在问题描述里解释一下。
让我以 Android 开发中一个简单的例子说明:在一个 Activity
中有多个可点击的按钮时,很多人会这么写:
public class ExampleActivity extends Activity implements OnClickListener {
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
findViewById(R.id.first_button).setOnClickListener(this);
findViewById(R.id.second_button).setOnClickListener(this);
}
@Override
public void onClick(final View v) {
switch (v.getId()) {
case R.id.first_button:
// bla bla bla
break;
case R.id.second_button:
// bra bra bra
}
}
}
事实上,Android 官方有些 sample 里面也是这么写的。然而在我看来,这么写代码是非常不优雅的,因为一个 OnClickListener
的实现,只应该关注和点击事件本身相关的内容,它的含义和 Activity
的含义是截然无关的,让同一个类继承/实现他们,会使得这个类的含义变得不清晰。同时,这样还给 ExampleActivity
类增加了一个 public
的方法,削弱了这个类的封闭性。
所以如果像下面这样,会好不少:
public class ExampleActivity extends Activity {
private OnClickListener onClickListener = new OnClickListener() {
@Override
public void onClick(final View v) {
switch (v.getId()) {
case R.id.first_button:
// bla bla bla
break;
case R.id.second_button:
// bra bra bra
}
}
};
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
findViewById(R.id.first_button).setOnClickListener(onClickListener);
findViewById(R.id.second_button).setOnClickListener(onClickListener);
}
}
这样写体现了 composition over inheritance 的思想。它避免了上面的所有问题,看起来舒服得多。
不过,这样还是让阅读代码时很不方便——看到 onCreate
里面时,还不得不经常滚动到声明 onClickListener
的地方去,并且在 onClick
中艰难的寻找真正和某个特定按钮相关的代码。当然这两个问题之前那个版本也都无法避免。
另一件糟糕的事情是,不同按钮的 listener 逻辑很可能是相对独立的,放到同一个 onClickListener
里,还是很丑陋。
所以为了进一步避免这几个问题,我一向都是用下面这样的写法:
public class ExampleActivity extends Activity {
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
findViewById(R.id.first_button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View v) {
// bla bla bla
}
});
findViewById(R.id.second_button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View v) {
// bra bra bra
}
});
}
}
这样的话,不同逻辑间相对独立,看起来非常舒服,便于阅读,并且让我找回了写 JavaScript 的舒畅感觉(划掉)。
那么问题来了:为什么有的人不使用最后一种写法呢,倒反是使用第一种写法呢?
我也比较赞同第二种写法,其优势你也都说到了,就不在赘述。但是一直奇怪为什么Google官方的例子为什么是按第一种方式写的,后来在Android的文档中看到一段话,大致内容是:Java创建对象其实开销是很大的,如果所有的监听都创建单独的对象,这样会使得程序产生非常多的额外开销。就是如此Google选择用同一个对象来完成所有的监听,这主要是因为早期Android设备性能不是特别好,只能在这种细节上节省性能,而现在设备都已经不在需要太关心这些了,所以用第二种方式也已经无伤大雅。