呃…… 标题不太好。让我在问题描述里解释一下。
让我以 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 的舒畅感觉(划掉)。
那么问题来了:为什么有的人不使用最后一种写法呢,倒反是使用第一种写法呢?
I also agree with the second way of writing. You have already mentioned its advantages, so I won’t go into details. But I have always wondered why Google’s official examples are written in the first way. Later, I saw a paragraph in the Android documentation, which roughly stated: Creating objects in Java is actually very expensive. If all listeners are created individually Object, this will cause the program to generate a lot of additional overhead. That's why Google chose to use the same object to complete all monitoring. This is mainly because the performance of early Android devices was not particularly good, and they could only save performance on such details. Now, devices no longer need to care too much about these, so use The second method is also harmless.
I personally prefer the last way of writing, and if
OnClickListener
there are a lot of things to do, I might write it as a named class separately.However, there are indeed many first ways of writing. I guess one reason is that the examples are misleading, because the example codes are usually relatively small, so there is no problem in writing this way, and the code will not be very long, but in actual business, the code may be much more; Another reason may be that some people think that writing classes is too heavyweight. Of course, in fact, writing classes is not necessarily more heavyweight than writing methods. This has theoretical and practical basis. Some people have done analysis, so I won’t say more.
In C#, delegates are used to implement the Click events of different buttons, and each delegate corresponds to a certain
XxxxButton_Click
method of the current Form (if it is a WinForm program, ASP.NET applications are similar). This writing method comes from the ancient It is inherited from VB/VC. Of course, the fact that UI Designer wants to do this cannot be ruled out. Due to the popularity of Lambda, more and more people are starting to use the third writing method similar to the original poster, but it is not an interface, it is just a Lambda - and there is a premise, without using UI Designer to generate code situation.Why speaking of C#, because Java has realized the superiority of Lambda, so it has also implemented Lambda, simulating the delegation of C# in the form of a single method interface, so the third way of writing can be simpler.
However, every transaction has two sides. Lambda provides convenience but also brings some inconvenience, especially when the logic is complex. Therefore, for event processing with more complex logic, I still recommend writing a separate processing class, which can be an implementation of an event interface (such as the implementation of OnClickListener), or an independent (or a bunch of related) business processing classes. Call in one sentence in onClick (such as
new Business(params).Go()
)composition over inheritance
How do you understand this term? Is composition better than inheritance? Because of the bad reputation of inheritance, everyone now preemptively rejects inheritance when they see it.
But is this really the case? I don't agree.
Object relationships in OO can be roughly divided into several relationships, such as association, dependence, combination, aggregation, inheritance, and generalization. These relationships stipulate the relationship between objects.
That is to say, the relationship between objects is whatever it is. To be precise, there is absolutely no combination. Due to the concept of inheritance, I don’t know because inheritance is easy to implement, so everyone likes to use inheritance for reuse. In fact, it is essentially Caused by insufficient object abstraction.
So some people simply put forward the idea that combination is better than inheritance to simplify everyone's thinking.
Back to the main question, why does Google implement it this way? From a business perspective, the life cycle of an activity will be in several stages. The entire object life cycle is implemented by Android. However, it is a very reasonable design to expose several key points through templates. I don't understand why the questioner would have such an idea.
This is foreigners’ deep understanding of program overhead. It has penetrated deep into the bone marrow.
I always use the second way of writing. When I first started learning Android, I used the third way. But if the listener has a lot of content, it doesn’t look very good.
I only write anonymous classes when there are very few listeners, and generally implement interfaces. If the click event code is large, I write a separate method and execute it in onClick. I think this code logic will be clearer and neater.
Abstract event processing into an entry process, and then abstract it into a common interface. This is a class concept, not specific to business.
The way you write it later is obviously specific to the concept of objects.
I am more accustomed to writing like this. Anyway, it is a specific business and a specific object, so there is no need to make it general

For objects that are used once, use them anonymously!
It’s just that the inner class will hold instances of the outer class, which can easily cause memory leaks
So in terms of performance, the first way of writing is better than the second way of writing, and the second way of writing is better than the third way of writing