xjtuer最好不要抄,五次作业都是去年优秀作业,如果因为全抄被老师逮住全给0分就得不偿失了,放在这里是给大家一个思路不用再去查找很多资料,了解之后再自己总结写一写
面向对象分析与设计中的基本事件处理的机制
分类
主要分为四种类型
同步调用
- 同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用
- 该方法是类A中的方法
a()
调用类B中的方法b()
,一直等待b()方法执行完毕,a()
方法才继续往下走,这种调用方式适用于方法b()
执行事件不长的情况,因为b()
方法执行时间比较长或者陷入死循环的话,a()
方法的余下代码是无法执行下去的,这样会造成整个流程的阻塞
回调函数
- 回调是一种双向的调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口
- 回调的思想是类A的方法
a()
调用类B的方法b()
,类B的方法b()
执行完后主动调用类A的callBack
方法Class A
实现接口CallBack
class B
中有一个参数为callback
的方法f(CallBack callback)
class A
中包含一个class B
的引用b- A的对象a调用B的方法
f(CallBack callback)
-----A类调用B类的某个方法C - b在
f(CallBack callback)
方法中调用A的方法-----B类调用A类的某个方法D
异步
- 为了解决同步调用可能出现阻塞, 导致整个流程卡住而产生的一种调用方式
- 该方法是类A的方法
a()
通过新起线程的方式调用类B的方法b()
,代码接着直接往下执行,这样无论方法b()
执行时间多久,都不会阻塞住方法a()
的执行,但是由于方法a()
不等待方法b()
的执行完成,在方法a()
需要方法b()
的执行结果的情况下必须通过一定的方式对方法b()
的执行结果进行监听
监听
- 监听器,字面上的理解就是监听观察某个事件(程序)的发生情况,当被监听的事件真的发生了的时候,事件发生者(事件源) 就会给注册该事件的监听者(监听器)发送消息,告诉监听者某些信息,同时监听者也可以获得一份事件对象,根据这个对象可以获得相关属性和执行相关操作。
- 事件源注册监听器之后,当事件源触发事件,监听器就可以回调事件对象的方法;更形象地说,监听者模式是基于:注册-回调的事件/消息通知处理模式,就是被监控者将消息通知给所有监控者。
代码分析
同步调用
在A类中main方法首先打印当前时间,然后调用B类的b()
方法,在b()
方法中,首先会暂停5秒模拟实际业务处理,然后打印当前系统时间,
运行结果如下
// A.java
package sync;
import java.text.SimpleDateFormat;
import java.util.Date;
public class A {
public static void main(String[] args) throws InterruptedException {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd hh:mm:ss");
System.out.println("这是A类中的a方法,现在的时间是:" + sdf.format(date));
B objectB = new B();
objectB.b();
System.out.println();
}
}
// B.java
package sync;
import java.text.SimpleDateFormat;
import java.util.Date;
public class B {
public void b() throws InterruptedException {
Thread.sleep(5000);
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd hh:mm:ss");
System.out.println("这是B类中的b方法,现在的时间是:" + sdf.format(date));
}
}
回调函数
该示例模拟学校中老师通知学生做任务的场景,在测试程序中,先向每个同学分配对应的监督老师(setCallback()
),接下来学生做任务(doTack()
),任务完成后自动通知老师学生任务完成(taskResult()
),然后老师接收到消息后打印学生姓名,
运行结果如下:
// CallbackTest.java
package callback;
public class CallbackTest {
public static void main(String[] args) throws InterruptedException {
String[] studentNameList = { "小红", "小明", "贝贝", "小方", "刘梦" };
String[] TeacherNameList = { "王洪", "王洪", "王洪", "黎鸣", "黎鸣" };
Student[] studentList = new Student[studentNameList.length];
for (int i = 0; i < studentList.length; i++) {
studentList[i] = new Student(studentNameList[i]);
studentList[i].setCallback(new Teacher(TeacherNameList[i]));//为每位同学分配监督老师
}
for (Student student : studentList) {
student.doTask();//学生做任务
}
}
}
// Teacher.java
package callback;
public class Teacher implements Callback {
String name;
public Teacher(String name) {
this.name = name;
}
@Override
public void taskResult(String stuName) {
System.out.println(this.name + "老师,学生[ " + stuName + " ]任务完成"); // 接收到学生的通知后打印学生姓名
}
}
// Student.java
package callback;
public class Student {
Callback callback;
String name;
public Student(String name) {
this.name = name;
}
public void setCallback(Callback callback) {
this.callback = callback; // 设置监督老师
}
public void doTask() throws InterruptedException {
Thread.sleep(1500);// 模拟学生做任务时间
callback.taskResult(name);// 通知老师任务已经完成
}
}
// Callback.java
package callback;
public interface Callback {
public void taskResult(String name);
}
异步调用
该示例模拟的场景是客户端向服务端发送请求,例如网页向后台发送注册表单,如果需要验证的信息过多,则前端网页需要等待时间过长,这时候可以先验证一些关键信息是否正确,然后向前端返回结果,同时服务器端在返回结果后继续处理数据存入数据库中
运行结果如下:
// test.java
package async;
public class test {
public static void main(String[] args) {
Server server = new Server();
Client client = new Client(server);
client.sendMsg("Server,Hello");
}
}
// Client.java
package async;
public class Client implements Callback {
private Server server;
public Client(Server server) {
this.server = server;
}
public void sendMsg(String msg) {
System.out.println("客户端:发送的消息是:" + msg);
new Thread(new Runnable() {
@Override
public void run() {
server.getClientMsg(Client.this, msg);
}
}).start();
System.out.println("客户端:消息发送成功");
}
@Override
public void result(String status) {
System.out.println("客户端:服务器返回状态为:" + status);
}
}
// Server.java
package async;
public class Server {
public void getClientMsg(Callback callback, String msg) {
System.out.println("服务端:接收到客户端发送的消息为:" + msg);
// 模拟服务器处理数据
try {
Thread.sleep(4000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println();
System.out.println("服务端:数据处理成功,返回状态 200");
String status = "200";
callback.result(status);
}
}
// Callback.java
package async;
public interface Callback {
public void result(String status);
}
监听
- 在该实例中,模拟了一个秒表,点击开始后每过1秒会计时一次,用户点击按钮会有不同的相应效果
- 使用
actionListener
监听器监听每个按钮的点击状态,点击后会设置signal
为相应的状态,此时计时器会执行相应的动作
运行结果如下:
开始后:
暂停时:
结束时:
// Test.java
package listener;
public class Test {
public static void main(String[] args) {
var listener = new Listener();
}
}
// Listener.java
package listener;
import javax.swing.*;
import java.awt.*;
public class Listener extends JFrame {
private JPanel buttonPanel;
private JTextArea textArea;
private int count;// 计数器
private int signal = 0;// 信号 1为开始 2为暂停 3为恢复 4为停止
public Listener() {
setSize(500, 300);// width height
setTitle("监听实例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 创建按钮组件
JButton Start = new JButton("Start");
JButton Pause = new JButton("Pause");
JButton resume = new JButton("resume");
JButton Stop = new JButton("Stop");
buttonPanel = new JPanel();
textArea = new JTextArea();
// 将按钮加入面板中
buttonPanel.add(Start);
buttonPanel.add(Pause);
buttonPanel.add(resume);
buttonPanel.add(Stop);
// 创建相关动作
Start.addActionListener(event -> signal = 1;);
Pause.addActionListener(event -> signal = 2);
resume.addActionListener(event -> signal = 3);
Stop.addActionListener(event -> signal = 4);
// 将面板及文字区域加入Frame中
add(buttonPanel);
add(buttonPanel, BorderLayout.NORTH);
add(textArea);
setVisible(true);
textArea.setText("现在已经计时" + 1 + "次");
// 模拟计时器
while (true) {
try {
Thread.sleep(1000);
if (signal == 1) {
count = 0;
signal = 3;
} else if (signal == 3) {
count++;
textArea.setText("现在已经计时" + count + "次");
} else if (signal == 4) {
textArea.setText("本轮共计时" + count + "次");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
对比分析
同步方法调用
同步调用是最基本的调用方式,对象b中的方法直接调用对象a的方法,这个时候程序会等待对象a的方法执行完返回结果之后才会继续往下走。
好处
- 代码书写以及阅读比较有逻辑性,事件处理具有顺序性
- 代码调试比较方便
缺点
- 代码的耦合度太高,可扩展性差,这种调用方法中一般结构以及代码都是固定死的,很难增加新的方法
- 适用于a中的方法执行时间较短的情况,时间较长的话会导致主程序等待较长时间才可继续执行
回调函数
好处
- 可以通过一个统一的接口实现不同的内容
- 降低了代码的耦合程度,提高了层次划分,适合团队协作(例如一个人写底层函数的时候,只需要告诉调用者回调函数的相关参数即可)
- 各个层次代码之间的影响降低
- 可以提高程序兼容性和扩展性
缺点
- 回调函数是一种破坏系统结构的设计,一般而言回调函数都会改变系统的运行轨迹,执行顺序和调用顺序
- 代码调试比较麻烦,容易出现回调地狱
异步调用
好处
- 可以很好的解决实际业务中服务器相应时间过长的场景
- 可以等多次调用的结果出来后统一返回一次结果集合,提高相应效率
- 不影响主线程的逻辑
- 可以增强系统的健壮性
缺点
- 只适用于没有时序上严格关系的场景
- 增加编程难度
监听
好处
- 事件的具体触发过程对开发人员是透明的,开发人员往往只需要写各种事件的回调函数接口
- 使用监听器后无需另外书写代码监听程序内部发生的某些事件,代码比较简单
- 支持同步异步调用方式
缺点
- 监听器的使用比较依赖系统框架