目录
在内部类中还有一种特殊的类,就是匿名内部类,那么使用匿名内部类会发现代码精简 程度更高。首先我们先回忆一下匿名内部类的特性:
- 匿名类是指没有指定名称的类。
- 匿名类最大的用途是编写事件处理程序。
- 匿名类的实质其实就是一个内部类,只是没有名称而已。
使用匿名内部类实现 MouseEvent 事件
package com.gui;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
public class LoginFrame extends JFrame {
private JPanel pnlMain;
//标签控件
private JLabel lblTitle;
private JLabel lblUserName;
private JLabel lblUserPwd;
//输入用户名的文本框控件
private JTextField txtUserName;
//输入密码的密码框控件
private JPasswordField pwdUserPwd;
//登录和退出按钮控件
private JButton btnLogin;
private JButton btnQuit;
public LoginFrame() {
//实例化各种容器和控件
pnlMain = new JPanel(null);
lblTitle = new JLabel("用户登录");
lblUserName = new JLabel("用户姓名:");
lblUserPwd = new JLabel("用户密码:");
txtUserName = new JTextField();
pwdUserPwd = new JPasswordField();
btnLogin = new JButton("登录");
btnQuit = new JButton("退出");
init();
}
//该方法对窗口做初始化
private void init() {
// 设置窗口属性
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("登录窗口");
this.setSize(300, 220);
this.setResizable(false);
/*
* 设置各个控件的位置和坐标
* setBounds 方法的前两个参数为控件的左上角坐标,后两个参数为控件的宽和高
*/
lblTitle.setBounds(100, 10, 100, 30);
lblUserName.setBounds(20, 60, 75, 25);
lblUserPwd.setBounds(20, 100, 75, 25);
txtUserName.setBounds(100, 60, 120, 25);
pwdUserPwd.setBounds(100, 100, 120, 25);
btnLogin.setBounds(50, 140, 75, 25);
btnQuit.setBounds(150, 140, 75, 25);
// 在用户姓名的文本框中添加默认文本
txtUserName.setText("请输入用户姓名");
// 在用户姓名的文本框上添加鼠标事件:使用匿名内部类
txtUserName.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
// 将登陆界面中的用户姓名文本框中的文本清除
txtUserName.setText("");
}
});
//将所有控件压在容器上
pnlMain.add(lblTitle);
pnlMain.add(lblUserName);
pnlMain.add(lblUserPwd);
pnlMain.add(txtUserName);
pnlMain.add(pwdUserPwd);
pnlMain.add(btnLogin);
pnlMain.add(btnQuit);
this.add(pnlMain);
this.setVisible(true);
}
//让鼠标监听类继承适配器后,只需要重写我们需要的方法即可
class LoginFrame_txtUserName_MouseListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
txtUserName.setText("");
}
}
}
使用外部类(自定义的一个独立于窗口类的监听实现类)实现事件。
使用内部类实现事件。
内部类配合使用适配器实现事件。
匿名内部类实现事件。
让窗口类实现事件监听接口,使其即为窗口又为事件监听类。
但是这么多种事件处理的方式,我们究竟该如何取舍呢?那是否是代码越少,质量越高 呢?其实我们完成代码不是以代码的多少进行取舍,而是要综合考虑代码的可维护性、可重 用性、负载问题等等。像后边四种方式代码耦合性高,这样如果需要更改业务逻辑或是界面 显示逻辑时,整个类就要修改,而且代码很难重用,尤其是匿名内部类(因为每使用一次就 重新产生一个新的类),对于并且窗口对象负载过重(既要负责显示、又要监听事件、还要 处理事件,相当于 3 个人的工作交给 1 个人完成)。所以综合考虑比较合适的还是第一种方 式。但是第一种仍然可以继续优化,因为它在监听类中完成了我们需要做的业务。这样监听 类功能不清,到底是做监听还是做业务?
综上所述,按照我们以前所学过得 OOP 编程思想,我们应该把这段代码分:视图层(窗 口界面,它只负责如何显示)、监听层(实现某个 Listener 的类,它只负责监听)、服务层 (只负责完成业务逻辑的实现),那么实现结构为:窗口中对事件源添加监听,在监听类中 的具体事件方法中调用服务层完成业务。
接下来我们使用这种模式完成一个用户登录按钮功能实现。首先定义一个用户模块下的最终父接口 UserService
分层开发实现事件—服务层之父接口 UserService
package com.gui;
import java.awt.Window;
import java.util.EventObject;
public interface UserService {
void execute(EventObject e,Window w);
}
该接口是用户模块下所有 Service 类的最终父接口。接下来定义三个服务层(登录按钮 服务层、退出按钮服务层、清空文本框服务层)的实现子类。
分层开发实现事件—服务层之登录按钮服务层
package com.gui;
import java.awt.Window;
import java.util.EventObject;
import javax.swing.JOptionPane;
/**
* 登陆功能服务层.
*/
public class LoginService implements UserService {
@Override
public void execute(EventObject e, Window w) {
LoginFrame lf = (LoginFrame)w;
String userName = lf.getTxtUserName().getText().trim();
//获得用户密码的密码框对象的文本内容
String userPwd = new String(lf.getPwdUserPwd().getPassword()).trim();
//验证用户账号是否填写
if(userName.equals("")) {
JOptionPane.showMessageDialog(null, "请输入用户姓名", "警告",
JOptionPane.WARNING_MESSAGE);
return;
}
if(userName.equals("zhangsan") && userPwd.equals("sxt")) {
/*
* 弹出对话框,第 1 个参数为窗口,所以可以传 null,
* 第 2 个参数为ᨀ示文本,第 3 个参数为标题信息,第 4 个参数为样式
*/
JOptionPane.showMessageDialog(null, "欢迎您:"+userName, "ᨀ示",
JOptionPane.INFORMATION_MESSAGE);
return;
}
JOptionPane.showMessageDialog(null, "用户姓名或密码错误", "错误",
JOptionPane.ERROR_MESSAGE);
}
}
分层开发实现事件—服务层之退出按钮服务层
package com.gui;
import java.awt.Window;
import java.util.EventObject;
/**
* 退出功能服务层.
*/
public class QuitService implements UserService {
@Override
public void execute(EventObject e, Window w) {
w.dispose();
}
}
分层开发实现事件—服务层之清空文本框服务层
package com.gui;
import java.awt.Window;
import java.util.EventObject;
/**
* 清空文本框服务层.
*/
public class ResetUserNameService implements UserService {
@Override
public void execute(EventObject e, Window w) {
LoginFrame lf = (LoginFrame)w;
lf.getTxtUserName().setText("");
}
}
接下来我们需要定义一个工厂类,获得具体服务层的对象
分层开发实现事件—服务层之工厂类
package com.gui;
/**
* 用户模块服务层工厂类.
*/
public abstract class UserServiceFactory {
/**
* 获得登陆功能业务逻辑对象.
*/
public static UserService createLoginService() {
return new LoginService();
}
/**
* 获得退出功能业务逻辑对象.
*/
public static UserService createQuitService() {
return new QuitService();
}
/**
* 获得清空文本框功能业务逻辑对象.
*/
public static UserService createResetUserNameService() {
return new ResetUserNameService();
}
}
然后,定义 3 个监听类(分别对应 3 个事件监听)
分层开发实现事件—监听层之登录按钮监听类
package com.gui;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LoginFrame_btnLogin_ActionListener implements ActionListener {
private LoginFrame lf;
private UserService service;
public LoginFrame_btnLogin_ActionListener(LoginFrame lf) {
this.lf = lf;
service = UserServiceFactory.createLoginService();
}
@Override
public void actionPerformed(ActionEvent e) {
service.execute(e, lf);
}
}
分层开发实现事件—监听层之退出按钮监听类
package com.gui;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LoginFrame_btnQuit_ActionListener implements ActionListener {
private LoginFrame lf;
private UserService service;
public LoginFrame_btnQuit_ActionListener(LoginFrame lf) {
this.lf = lf;
service = UserServiceFactory.createQuitService();
}
@Override
public void actionPerformed(ActionEvent e) {
service.execute(e, lf);
}
}
分层开发实现事件—监听层之清空文本框监听类
package com.gui;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
/**
* 清空文本框功能监听类.
*/
public class LoginFrame_txtUserName_MouseListener extends MouseAdapter {
private LoginFrame lf;
private UserService service;
public LoginFrame_txtUserName_MouseListener(LoginFrame lf) {
this.lf = lf;
service = UserServiceFactory.createResetUserNameService();
}
@Override
public void mouseClicked(MouseEvent e) {
service.execute(e, lf);
}
}
最后,我们定义一个窗口类
分层开发实现事件—视图层之窗口类
package com.gui;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
public class LoginFrame extends JFrame {
private JPanel pnlMain;
//标签控件
private JLabel lblTitle;
private JLabel lblUserName;
private JLabel lblUserPwd;
//输入用户名的文本框控件
private JTextField txtUserName;
//输入密码的密码框控件
private JPasswordField pwdUserPwd;
//登录和退出按钮控件
private JButton btnLogin;
private JButton btnQuit;
public LoginFrame() {
//实例化各种容器和控件
pnlMain = new JPanel(null);
lblTitle = new JLabel("用户登录");
lblUserName = new JLabel("用户姓名:");
lblUserPwd = new JLabel("用户密码:");
txtUserName = new JTextField();
pwdUserPwd = new JPasswordField();
btnLogin = new JButton("登录");
btnQuit = new JButton("退出");
init();
}
//对文本框对象和密码框对象添加 get 方法
public JTextField getTxtUserName() {
return txtUserName;
}
public JPasswordField getPwdUserPwd() {
return pwdUserPwd;
}
//该方法对窗口做初始化
private void init() {
// 设置窗口属性
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("登录窗口");
this.setSize(300, 220);
this.setResizable(false);
/*
* 设置各个控件的位置和坐标
* setBounds 方法的前两个参数为控件的左上角坐标,后两个参数为控件的宽和高
*/
lblTitle.setBounds(100, 10, 100, 30);
lblUserName.setBounds(20, 60, 75, 25);
lblUserPwd.setBounds(20, 100, 75, 25);
txtUserName.setBounds(100, 60, 120, 25);
pwdUserPwd.setBounds(100, 100, 120, 25);
btnLogin.setBounds(50, 140, 75, 25);
btnQuit.setBounds(150, 140, 75, 25);
/*
* 在退出按钮上添加按钮按下监听对象,
* 并在实例化监听对象中传入当前窗口对象本身
*/
btnQuit.addActionListener(
new LoginFrame_btnQuit_ActionListener(this));
/*
* 在登录按钮上添加按钮按下监听对象,
* 并在实例化监听对象中传入当前窗口对象本身
*/
btnLogin.addActionListener(
new LoginFrame_btnLogin_ActionListener(this));
//在用户姓名的文本框中添加默认文本
txtUserName.setText("请输入用户姓名");
//在用户姓名的文本框上添加鼠标事件
txtUserName.addMouseListener(
new LoginFrame_txtUserName_MouseListener(this));
//将所有控件压在容器上
pnlMain.add(lblTitle);
pnlMain.add(lblUserName);
pnlMain.add(lblUserPwd);
pnlMain.add(txtUserName);
pnlMain.add(pwdUserPwd);
pnlMain.add(btnLogin);
pnlMain.add(btnQuit);
this.add(pnlMain);
this.setVisible(true);
}
}
通过分 层开发的思想实现了“窗口中对事件源添加监听,在监听类中的具体事件方法中调用服务层 完成业务”的逻辑,使代码逻辑更加清晰。