上周看代码的时候,看到一坨shit(其实shit很多,我自己也经常写出Shit)如果由自己来想,如何写出优雅的代码呢?
场景: 初步请求其实再简单不过, 就是一个经典的 请求处理接口
int Handle( Buffer * ptBuffReq, Buffer * ptBuffResp )
网络层将请求包收到后(验证请求包正确后), 将请求包的内容,交给Handle去处理。
Handle 的处理流程: A版本
1 从ptBufferReq 反序列化出具体结构体stReq;
2 具体逻辑处理, 处理结果stReq;
3 序列化 stResp 到ptBufferResp;
代码在这个时候还是很清晰,并且层次分明的。
需求变更:需要在原有的逻辑处理,希望打印所有的请求类型 stReq.type及其他参数 到日志中。
于是Handle的处理流程:
1 从ptBufferReq 反序列化出具体结构体stReq;
2 (插入代码Log(stReq.type)) 具体逻辑处理, 处理结果stReq;
3 序列化 stResp 到ptBufferResp;
需求再变更: 请求量大,日志开销较大,对请求进行抽样大
继续在Handle 这个接口中 加入 if( 抽样范围 ) Log 的代码。
需求变更持续ing: 异步分析请求合法性功能, 染色Log(一旦被染色中都打log), 开关这些后续添加的功能。
Handle的代码终于 shit 一般了。虽然勉强可读,确实已经 很恶心了。
这种场景,我们描述为: 接口职责不变,接口 功能增加,且要求功能能灵活组合,开关
装饰模式在这种场景下,非常适用: 不改变其接口职责,动态组合增加的功能 。
如何做呢?
class VHandle 纯虚函数 Handle;
具体子类 class HandleImpl Handle 实现 A版本的 流程。
抽象插件子类 class HandlePlugin 其构造函数要求传入 一个VHandle的指针. Handle() 实现是m_ptVHanlde->Handle(), 再回调一个纯虚函数, PluginHandle();
具体插件子类 AsyncAnalyseHandle, StatLogHandle 继承 HandlePlush. 并在PluginHandle实现自己的具体逻辑z。
具体类图如:
现在这堆代码已经很灵活了,可以根据配置文件达成各种组装。
比如: VHandle * ptHandle = new HandleImpl();
VHandle * ptHandlePlugedAsyncAnalyse = new AsyncAnalyseHandle( ptHandle );
VHandle * ptHandlePlugedAll = new StatLogHandle( ptHandlePlugedAsyncAnalyse );
ShowCase 就到这了。 还有各种非常优雅的应用, 装饰模式非常好用,顶一个。