Listener
Zeze支持在Table中注册数据变更监听器,当数据发生变化时,回调监听器。不管什么修 改操作,不管有多少修改操作,只要对数据进行了修改,都能得到通知。只要数据定义没有 变化,修改操作随意变化,监听逻辑都保持不变。这个功能非常一般用于同步数据给客户端。 除非逻辑接近事件这种模型,否则不要用监听器实现逻辑。
分布式
分布式情况下,Server有多台实例。此时Listener在每个Server上都注册。以后哪台Server 发生了修改,就回调哪一台上的Listener。Listener这个模式不能算是一个良好的分布式定 义,需要注意。
接口
public interface ChangeListener {
void OnChanged(Object key, Changes.Record r);
}
例子
public static class ItemsChangeListener implements ChangeListener {
void OnChanged(Object key, Changes.Record r) {
switch (r.getState()) {
case Changes.Record.Put:
// 记录整个被替换。
break;
case Changes.Record.Edit:
// 增量变化,
var notemap2 = (LogMap2<Integer, BItem>)
c.getVariableLog(tequip.VAR_Items);
if (null != notemap2) {
// 访问详细日志。对于这里的LogMap2,note里面包含
// Replaced(被替换的项),
// Removed(被删除的项),
// Changed(Map中的项是一个Bean并且发生了变化)
// 由于同步Map的数据时,Changed通常可以合并到Replaced中。
// 所以首先调用下面的方法合并。
notemap2.MergeChangedToReplaced();
// 然后把Replaced,Removed打包到协议中发送给客户端。
}
break;
case Changes.Record.Remove:
// 记录删除
break;
}
}
}
注册
_tequip.getChangeListenerMap().AddListener(new ItemsChangeListener());
客户端收到数据变化协议的处理伪码
Switch (ItemsChangeNotify.getChangeTag()) {
Case Put:
Localmap.clear();
Localmap.putAll(ItemsChangeNotify.Replaced());
// Put时Removed没有意义。
Break;
Case Edit:
Localmap.putAll(ItemsChangeNotify.Replaced());
Localmap.removeAll(ItemsChangeNotify.Removed());
Break;
Case Remove:
Localmap = null;
Break;
}
变更日志
- Bean的日志LogBean,包含IntHashMap
Variables - List1的日志LogList1,包含List的操作日志。
- List2的日志LogList2,包含List的操作日志以及List中的项修改的Changed。
- Map1的日志LogMap1,包含Replaced,Removed。
- Map2的日志LogMap2,包含Replaced,Removed,Changed。
- Set的日志LogSet1,包含Added,Removed。
- 简单类型(如int)的日志,包含新的值Value。
数据同步模式探讨
探讨的问题
- 客户端数据怎么从服务器获取和同步?
- 客户端获取数据的时机?
- 客户端数据存储(生命期)探讨?
数据获取(侧重和服务器交互)
- Get 模式
客户端主动发送Get请求,服务器返回结果。 【这个模式大大的推荐!】
- Push模式
客户端缓存数据,并且通过交互协议与服务器数据进行同步,客户端数据总是最新的。一般 用于登录期间一直有效的数据。客户端初始Get一次或者0 Get或者订阅方案。服务器主动 通告最新数据给客户端。
- Push 完整数据
当服务器发现数据变更时,把最新数据打包Push给客户端。客户端数据结构和服务器数据 结构不一致,打包时可做翻译。这个模式结构清晰,实现简单。 【这个模式大大的推荐!】
- Push 不完备增量更新
客户端主动Get一次数据,以后服务器Push增量更新给客户端。这里不完备的意思是仅打 包部分修改Log(比如Bean的第一级变量的Map,Set类型相关的修改数据)。 【这个模式限制使用!迫不得已时采用!】 这个模式有两个问题:a)Get和增量更新原子问题。b)增量更新消息丢失。这两个问 题的推荐解决方案:在数据中记录一个修改版本号,修改时递增;Push时带上版本号;客 户端发现版本号出现错误,重新Get再次开启新的增量流程。
- Push 完备增量更新
完备的意思是任何Bean结构的增量更新。在客户端实现这个需要的代码较多。目前只有 conf+cs+net支持(还没测试过)。 【这个模式暂时不推荐使用!】
- Zeze.Listener 的使用场景(限制)
Listener适合同步个人数据。比如角色包裹,服务器监听Listener,发现改变发送push-notify 给该包裹拥有者,客户端接收push-notify并更新本地数据。Listener不适合更新共享的数 据,比如群成员列表这个数据的变化,虽然可以发notify广播,但有点浪费,【实在要使用 也可以考虑这样做】。
客户端数据获取时机
- 在Loading界面准备数据,然后一起显示。
- 先显示UI,然后获取数据,再逐渐显示出来。
- 客户端时机点
- 全局数据管理器
不够灵活,不太容易满足各种需求。
- 模块自己管理
个人建议这一种。当模块需要热拔插时尤其需要这种。