深入浅出:事件监听中的适配器模式

1. 为什么需要适配器模式?

在Java的事件监听器设计中,许多接口有多个抽象方法。例如,MouseListener 接口有 5 个方法,KeyListener 接口有 3 个方法。如果我们只关心其中的一个方法(例如,鼠标点击事件),实现完整的接口就显得过于冗长和繁琐。为了避免实现那些我们不需要的方法,适配器模式应运而生。

2. 适配器模式的实现

适配器模式提供了一个抽象的适配器类,允许我们只重写我们感兴趣的方法,而不必实现接口的所有方法。Java通过 适配器类 提供了这一功能,比如 MouseAdapter、KeyAdapter 和 WindowAdapter 等,它们为每个接口提供了默认的空实现,允许我们根据需要只覆盖感兴趣的方法。

适配器模式的核心思想:
  • 抽象类(Adapter):提供接口的默认空实现,避免强制要求实现接口的所有方法。
  • 客户端:通过继承适配器类并重写部分方法,来减少代码量和增强可读性。

3. 示例:使用适配器模式

MouseListener 接口的适配器:MouseAdapter

MouseListener 接口定义了 5 个方法:

  • mouseClicked(MouseEvent e)
  • mousePressed(MouseEvent e)
  • mouseReleased(MouseEvent e)
  • mouseEntered(MouseEvent e)
  • mouseExited(MouseEvent e)

但假如只关心 mouseClicked 方法,使用适配器模式就显得非常方便。

java 复制代码
import java.awt.*;
import java.awt.event.*;

public class MouseAdapterExample {
    public static void main(String[] args) {
        // 创建窗口
        Frame frame = new Frame("MouseAdapter Example");

        // 创建一个按钮
        Button button = new Button("Click Me");

        // 使用 MouseAdapter 适配器,只关心 mouseClicked 方法
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("Button clicked!");
            }
        });

        // 设置按钮的位置和大小
        button.setBounds(100, 100, 100, 50);
        frame.add(button);

        // 设置窗口属性
        frame.setSize(300, 200);
        frame.setLayout(null);
        frame.setVisible(true);
    }
}
  • MouseListener 接口定义了 5 个方法,但我们只关心 mouseClicked 方法。
  • 通过继承 MouseAdapter(它是 MouseListener 的一个适配器类),我们只需要重写我们感兴趣的 mouseClicked 方法,其他方法会有默认的空实现。
  • 这大大减少了代码的冗余和复杂性。
KeyListener 接口的适配器:KeyAdapter

类似于 MouseListener,KeyListener 接口也有 3 个方法:

  • keyPressed(KeyEvent e)

  • keyReleased(KeyEvent e)

  • keyTyped(KeyEvent e)

如果只关心 keyPressed 事件,可以使用 KeyAdapter 适配器。

java 复制代码
import java.awt.*;
import java.awt.event.*;

public class test {
    public static void main(String[] args) {
        // 创建窗口
        Frame frame = new Frame("KeyAdapter Example");

        // 创建一个文本框
        TextField textField = new TextField();
        textField.setBounds(50, 100, 200, 30);

        // 使用 KeyAdapter 适配器,只关心 keyPressed 方法
        textField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                System.out.println("Key pressed: " + e.getKeyChar());
            }
        });

        // 将文本框添加到窗口
        frame.add(textField);

        // 设置窗口属性
        frame.setSize(300, 200);
        frame.setLayout(null);
        frame.setVisible(true);
         frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
}
  • KeyListener 接口定义了 3 个方法,但我们只关心 keyPressed 方法。
  • 使用 KeyAdapter,我们只需要实现 keyPressed 方法,其他两个方法(keyReleased 和 keyTyped)可以保持空实现。

4. 适配器模式的优点

  1. 简化代码:适配器模式允许我们只实现感兴趣的方法,避免了必须实现所有方法的冗余代码。这使得代码更加简洁。

  2. 提高可读性:在实现接口时,我们只会关注需要的部分,其他部分通过适配器的空实现处理,代码更具可读性。

  3. 增强灵活性:适配器模式让我们可以在不修改原始接口的情况下,仅通过继承适配器类来改变行为。这对扩展和维护代码很有帮助。


5. 适配器模式与观察者模式

在AWT和Swing的事件模型中,适配器模式与观察者模式相结合。事件监听器实现了 观察者模式,而适配器模式则使得事件监听器的使用变得更加灵活和简洁。

  • 观察者模式 :事件源(如按钮、文本框等)是 被观察者 ,监听器是 观察者,当事件发生时,事件源通知监听器进行处理。
  • 适配器模式:通过适配器类,开发者不需要实现所有的事件处理方法,只需关注自己关心的事件。

6. 总结

  • 适配器模式 是为了简化实现接口的过程,尤其是当接口包含多个方法时。通过继承适配器类并只重写需要的方法,我们可以避免实现多余的代码。
  • 在Java的AWT和Swing中,适配器类 (如 MouseAdapter、KeyAdapter、WindowAdapter)是非常常见的应用,它们帮助我们简化事件处理的代码,特别是当我们只关心事件接口的部分方法时。
相关推荐
知识搬运临时工20 分钟前
JVM 删掉偏向锁之后,一次无竞争锁从 0.3 纳秒变成 5.4 纳秒
java
IT枫斗者枫哥24 分钟前
用了BigDecimal还差一分?用四组Java代码查清原因
java·后端
一条泥憨鱼1 小时前
【消息队列】ACK确认了什么:消息队列可靠投递的完整链路
java·后端·kafka·消息队列·rabbitmq
yangmu32031 小时前
编程语言发展简史:从机器指令到智能协作
开发语言
从琳开始9892 小时前
网络原理入门(二)------OSI七层模型?TCP/IP五层(四层)模型原来是这样的
java·网络·tcp/ip·java-ee·php
文丑颜不良啊2 小时前
LeetCode1861~1880题目解析
java·leetcode
Flynn Liang2 小时前
AgentScope Java 深度解析:ReActAgent、HarnessAgent 与多智能体编排——JVM 上的自治 Agent 底座
java·大模型·架构设计·ai agent·spring ai·langchain4j·agentscope
Flynn Liang2 小时前
上线后怎么排查 AI 调用?Spring AI Observability:token/延迟/成本埋点与全链路追踪
java·人工智能·spring·监控·可观测性·observability·springai
文丑颜不良啊2 小时前
LeetCode1921~1940题目解析
java·leetcode
Tt有了t3 小时前
设计模式速查
java·python·设计模式