为了一个简单的好例子,让我们假设操作系统是用 Java 编写的。然后我们会有一个类Mouse,以及许多想要响应鼠标点击的应用程序。
一种简单的方法是让每个应用程序不断询问鼠标当前是否按下了鼠标按钮:
class MyApplication {
void run() {
for (;;) {
if (Mouse.isLeftButtonDown()) {
// do something
}
}
}
}
这有一个缺点,如果没有按下鼠标按钮,我们有一个线程不断执行该循环。如果每个应用程序都这样做,这尤其糟糕。您的 CPU 会一直忙于检查鼠标,不必要地消耗能量,并导致其他进程和程序变慢。第一个改进是在循环中添加一个短暂的睡眠延迟:
class MyApplication {
Mouse mouse;
void run() {
for (;;) {
if (mouse.isLeftButtonDown()) {
// do something
}
Thread.sleep(50);
}
}
}
这将节省 cpu 时间,但如果鼠标按钮按下的时间少于 50 毫秒(或者程序错误的应用程序的另一个线程占用了 cpu,导致我们的线程无法运行),应用程序可能不会注意到点击。
这些问题可以通过使用观察者模式巧妙地避免,鼠标作为主体,各种应用程序(或窗口)作为监听器:
class MyApplication implements MouseListener {
MyApplication() {
Mouse.subscribe(this);
}
@Override onLeftClick() {
// do something
}
void close() {
Mouse.unsubscribe(this);
}
}
当然,这本身只是将检测鼠标点击的问题从应用程序转移到了操作系统。操作系统可能仍然有一个专用的点击观察线程(这已经比每个应用程序的点击观察线程更加资源友好)。但是操作系统可以反过来使用观察者模式,通过为hardware interrupt 安装一个事件监听器,将监听点击委托给实际硬件。使用该解决方案,通过鼠标本身的简单电路来监视点击,它可以非常高保真地检测鼠标点击,而不会占用 CPU 进行不必要的繁忙工作。
简而言之,像可靠地检测鼠标点击这样基本的事情不会以我们习惯的可靠性和效率来完成,如果不是因为洞察到通知事件比不断检查是否更方便我们自己发生了一件事情。