引言一.使用代理模式控制流程
1.代理模式解决了什么问题?
a.什么是代理模式?b.代理模式解决了什么问题? 2.我的实践
a.思路b.时序图 二.数据同步与界面刷新附录
1.需求示意图
a.主界面b.二级界面-mod详情c.三级界面-作者名片 2.代理类关键代码参考
a.代理请求的注册与反注册b.代理请求流程控制c.代理请求回调处理 3.客户类关键代码参考
a.注册和反注册代理请求b.请求
引言最近一个月给mod编辑器做一个类似应用商店的UI模块,总结了经验和教训与大家分享一下~
部分关键代码贴在附录,新手朋友可以参考下。
引用菜鸟教程的解释:在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。举个例子,在携程上买机票,其实携程并不卖票,只是帮客户向南航、山航等各大航空公司买票,并提供一些服务。也就是一个类(携程)代表了另一个类的功能(航空公司)。
b.代理模式解决了什么问题?还是以买票举例,客户为啥不直接向航空公司买票,而选择携程这个“中间商赚差价”呢?如果客户直接向航空公司买票,需要先查询相关航线,在查询附近机场,还要跑到航空公司买票,自己预定接送机,酒店… 若使用携程,只要输入出发地、目的地,携程会帮客户算好线路,客户只要点一下就好了,携程会帮客户买票,订接送机,订酒店… 只需要多付一点钱,便可以更加方便智能的乘机。
回到程序设计,代理类向用户类提供服务,反过来说用户类的相关流程被代理类控制。主要优点是可以提供统一的接口进行流程控制,对客户类和服务类(航空公司)解耦,缺点则在于会多一些函数调用。
此功能模块涉及大量的http请求及相关回调,且有一些相同的参数(parentGameId,languageType…)以及相同控制操作(请求间隔,请求阻塞,广播回调数据等)。故采取代理类作为UI和http的中间层进行控制和解耦。主要提供以下服务:
- 代理请求的增改删查代理请求的间隔阻塞控制,同时也支持强制请求请求失败错误日志打印请求数据的埋点代理事件回调
对于一些需要常驻内存的数据,最好采取统一的数据内存管理。换而言之,就是对于
同一份数据不要存在副本。可以搞一个数据管理层,当数据层数据更新时,通知监听者(在这里就是一些显示层)我的数据变了,让监听者自行决定是否进行更新数据或者显示。
local DelegateDic = {}
function ModAsyncProxy:regDelegateRequest(key,req,backEvent,cb,interval)
if not (key and req and backEvent and type(req) == "function") then
Lib.logDebug("!!!ModAsyncProxy param is error")
return
end
if DelegateDic[key] ~= nil then
Lib.logDebug("!!!ModAsyncProxy this key has reg,key: "..key)
return
end
DelegateDic[key] = {
key = key,
req = req,
event = backEvent,
lastReqTimeStamp = -1,
isReq = false,
interval = interval or 0,
cb = cb
}
end
function ModAsyncProxy:unRegDelegateRequest(key)
if not key then
return
end
DelegateDic[key] = nil
end
function ModAsyncProxy:clear()
for k,v in pairs(DelegateDic) do
self:unRegDelegateRequest(k)
end
end
b.代理请求流程控制
function ModAsyncProxy:request(key,...)
local info = DelegateDic[key]
if not info then
Lib.logDebug("this key not register,key:"..key)
end
if info.isReq == true then
return
end
if os.time() - info.lastReqTimeStamp < info.interval then
return
end
self:doRequest(key,...)
end
function ModAsyncProxy:forceRequest(key,...)
self:doRequest(key,...)
end
function ModAsyncProxy:doRequest(key,...)
local info = DelegateDic[key]
info.isReq = true
info.lastReqTimeStamp = os.time()
info.req(function(resp,isSuccess,url,param,body)
self:onResponse(key,resp,isSuccess,url,param,body)
end,...)
end
c.代理请求回调处理
local PrintErrorInfo = function(key,code,url,param,body)
local errorInfo = {
key = key,
code = code,
url = url,
param = param,
body = body
}
Lib.logInfo("=== Mod Request Error info: ",errorInfo)
end
function ModAsyncProxy:onResponse(key,resp,isSuccess,url,param,body)
local info = DelegateDic[key]
if not info then
return
end
info.isReq = false
if not isSuccess then
PrintErrorInfo(key,resp.code,url,param,body)
return
end
Lib.logInfo("===Receive ModAsync Key:"..key,resp.data)
if info.event then
Lib.emitEvent(info.event,resp.data)
end
if info.cb then
info.cb(resp.data)
end
end
3.客户类关键代码参考
a.注册和反注册代理请求
--注册请求 ---@type ModAsyncProxy local ModAsyncProxy = T(Lib,"ModAsyncProxy") function WidgetModSearch:init() -- ...... self.reqSearchKey = "ModSearch_Search" ModAsyncProxy:regDelegateRequest(self.reqSearchKey,AsyncProcess.GetSearchModGameList, Event.EVENT_MOD_RESPONSE_MAP_SEARCH) self._allEvent[#self._allEvent + 1] = Lib.subscribeEvent(Event.EVENT_MOD_RESPONSE_MAP_SEARCH, function(data) self:onResponseSearch(data) end) end --反注册 function WidgetModSearch:onDestroy() if self._allEvent then for k, fun in pairs(self._allEvent) do fun() end end ModAsyncProxy:unRegDelegateRequest(self.reqSearchKey) endb.请求
function WidgetModSearch:requestModSearchMap(pageNo) local pageNo = pageNo or (self.pageNo + 1) local pageSize = Define.ModSearchItemonceNum local keyWord = self.keyWord ModAsyncProxy:request(self.reqSearchKey,keyWord,pageNo,pageSize) end
``



