java 实现事件_用Java实现事件驱动框架(二)

本文将基于上一篇用Java实现事先驱动框架(一)来模拟实现一个简单的聊天室系统

结构设计

首先确定简单聊天系统的基本对象。系统需要两种基本数据结构:用户与聊天室。

用户类

用户的定义如下。每一个进行聊天的用户都有一个名字。

private static class User {

public String name;

public User(String name) {

this.name = name;

}

}

聊天室类

聊天室需要维护当前在聊天室中的用户,其结构如下。

private static class ChatState {

private ArrayList users;

public ChatState() {}

}

行为

首先思考一下,一个聊天室程序包含的基本事件。

用户到来:当用户进入聊天时产生该事件。

用户离开:当用户离开聊天时产生该事件。

用户发消息:当用户在聊天时发送消息时产生该事件。

聊天室与用户应能够响应并处理与自身相关的事件。下面将详细描述具体实现。

聊天室的行为状态

聊天室应能够处理与其相关的事件。因此需要能够支持下列操作。

添加用户到聊天室

将用户从聊天室删除

广播消息给所有聊天室中的用户

广播消息的接受者是所有的用户。ChatState类将实现上述聊天室的行为。

private static class ChatState {

private ArrayList users;

public ChatState() {}

public void broadcast(Event evt) {}

// Mutators

public void addUser(User user) {}

public void removeUser(User user) {}

}

实现很简单,用户列表维护了当前在聊天的用户,事件可以广播给每位用户。

private static class ChatState {

private ArrayList users;

public ChatState() {

this.users = new ArrayList();

}

public void broadcast(Event evt) {

for (User recipient : users)

recipient.dispatch(evt);

}

// Mutators

public void addUser(User user) {

users.add(user);

}

public void removeUser(User user) {

users.remove(user);

}

}

ChatState负责将事件广播给每位注册的用户。

用户状态行为

用户类的基本实现如下。因为用户类能够接收事件,并且需要对接收到的事件进行处理。用户类实现如下。

private static class User {

public String name;

public User(String name) {

this.name = name;

}

// Event demultiplexing

public void dispatch(Event evt) {

if (evt.getClass() == UserMessage.class) {

UserMessage message = (UserMessage) evt;

processMessage(message.user, message.message);

}

}

// Event processing

public void processMessage(User user, String userMessage) {

// Ignore messages by me

if (user.equals(this))

return;

System.out.println(

name + " received message from " +

user.name

);

}

}

在dispatch方法中,Event类型的参数会与UserMessage.class进行比较,如果是UserMessage.class则进行处理。

聊天室与事件处理器

当产生聊天室的相关事件,需要有相关的处理器进行处理。因此需要注册相关事件及其事件处理器。

state.registerChannel(UserArrival.class, new ChatHandler() {

@Override

public void dispatch(Event evt) {

UserArrival arrival = (UserArrival) evt;

arrival.state.addUser(arrival.user);

System.out.println(

arrival.user.name + " has entered the room."

);

}

});

上述代码中将聊天室对象作为事件的一个成员,这样每增加一个事件,就需要关联一个聊天室对象。例如UserArrival, UserDeparture与UserMessage三个事件都必须存储一个聊天室对象的引用。这样就产生了重复代码。为了解决这个问题,可以创建一个包装类来维护聊天室对象的引用。通过ChatHandler保存一个ChatState的引用。

private static class ChatHandler extends Handler {

protected ChatState state;

public ChatHandler(ChatState state) {

this.state = state;

}

}

事件注册方法则更新为如下形式。通过帮助类registerHandlers来将事件和处理方法注册。ChatHandler内部维护了ChatState的引用,而所有关于聊天室的事件处理均由ChatState提供的相关方法来处理。

public static void registerHandlers(EventDispatcher dispatcher, ChatState state) {

dispatcher.registerChannel(UserArrival.class, new ChatHandler(state) {

@Override

public void dispatch(Event evt) {

UserArrival arrival = (UserArrival) evt;

state.addUser(arrival.user);

System.out.println(

arrival.user.name + " has entered the room."

);

}

});

dispatcher.registerChannel(UserDeparture.class, new ChatHandler(state) {

@Override

public void dispatch(Event evt) {

UserDeparture departure = (UserDeparture) evt;

state.removeUser(departure.user);

System.out.println(

departure.user.name + " has left the room."

);

}

});

dispatcher.registerChannel(UserMessage.class, new ChatHandler(state) {

@Override

public void dispatch(Event evt) {

UserMessage message = (UserMessage) evt;

String userMessage =

String.format(

"%s: %s",

message.user.name,

message.message

);

System.out.println(userMessage);

// Broadcast messages

state.broadcast(message);

}

});

}

事件生成

用户发消息会产生响应的事件。产生的事件会放入事件队列中。因此用户类内部增加事件队列的引用。

private static class User {

public Queue eventQueue;

public String name;

public User(Queue eventQueue, String name) {

this.eventQueue = eventQueue;

this.name = name;

}

// Behavioral methods

}

接着为用户增加方法,将产生的事件放入事件队列中。

private static class User {

public Queue eventQueue;

public String name;

public User(Queue eventQueue, String name) {

this.eventQueue = eventQueue;

this.name = name;

}

// Event demultiplexing and handling methods

// Event generation

public void sendMessage(String message) {

eventQueue.add(new UserMessage(this, message));

}

}

这样用户可以进行消息发送,并且不需关心事件的转发。

使用事件队列

接着创建事件队列来存放产生的事件。

import java.util.LinkedList;

// ChatState declaration here

public static void main(String[] args) {

EventDispatcher dispatcher = new Dispatcher();

ChatState state = new ChatState();

Queue eventQueue = new LinkedList();

// Further simulation code such as event handler registration

}

接着创建转发器,转发器不断地从队列中取出事件,然后转发给响应的处理器进行处理。

import java.util.LinkedList;

// ChatState declaration here

public static void main(String[] args) {

EventDispatcher dispatcher = new Dispatcher();

ChatState state = new ChatState();

Queue eventQueue = new LinkedList();

// Further simulation code such as event handler registration

// Possibly generate events beforehand

// Dispatch all queued events

while (!eventQueue.isEmpty()) {

Event evt = eventQueue.remove();

dispatcher.dispatch(evt);

}

}

事件队列并不会与聊天室对象交互,仅用事件生成者进行关联。而用户就是一个事件生生成者。因此为用户对象增加事件队列的引用。

private static class User {

public Queue eventQueue;

public String name;

public User(Queue eventQueue, String name) {

this.eventQueue = eventQueue;

this.name = name;

}

// Behavioral methods

}

当用户生成相关事件后,事件被加入到队列中。

private static class User {

public Queue eventQueue;

public String name;

public User(Queue eventQueue, String name) {

this.eventQueue = eventQueue;

this.name = name;

}

// Event demultiplexing and handling methods

// Event generation

public void sendMessage(String message) {

eventQueue.add(new UserMessage(this, message));

}

}

这样一个基于事件驱动的简单聊天室系统就构建完毕了。

模拟测试

public static void main(String[] args) {

EventDispatcher dispatcher = new EventDispatcher();

ChatState state = new ChatState();

Queue eventQueue = new LinkedList();

registerHandlers(dispatcher, state);

// Initialize users

User foo = new User(eventQueue, "foo");

User bar = new User(eventQueue, "bar");

dispatcher.dispatch(new UserArrival(foo));

dispatcher.dispatch(new UserArrival(bar));

// Enqueue events from individual users

foo.sendMessage("hello, bar!");

bar.sendMessage("hello, foo!");

foo.sendMessage("goodbye, bar!");

// Dispatch all queued events

while (!eventQueue.isEmpty()) {

Event evt = eventQueue.remove();

dispatcher.dispatch(evt);

}

// Finish up simulation

dispatcher.dispatch(new UserDeparture(foo));

dispatcher.dispatch(new UserDeparture(bar));

}

上述代码将产生输出

foo has entered the room.

bar has entered the room.

foo: hello, bar!

bar: hello, foo!

foo: goodbye, bar!

foo has left the room.

bar has left the room.

总结

本文使用Java实现事先驱动框架(一)中实现的事件驱动框架来模拟一个聊天室程序。当事件源产生事件后,将事件加入到了事件队列中。而事件转发器不断的尝试从事件队列中取事件,然后使用事件处理器进行处理。系统基于事件驱动框架构建,通过这个实例对事件驱动模型的简单实现有了一定的认识。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值