简单干净的C#方法设计案例:SFCUI.AjaxValue()之三
之前讲到,方法声明为:
调用的例子:
感觉上toggle、弹出菜单、UpdateTargetID什么的都没有啊,怎么能实现?
这就是设计的一种重要原则:把所有技术细节都隐藏在实现的内部。
函数内部的设计
下面的代码仅作示例,与我自己用的不太一样,简化了一下,只为说明问题。
这样,函数里边就把放置Value的DIV(也就是日后会被更新的那个)、弹出菜单、弹出菜单上应该写的东西、点击后该干什么、弹出后该干什么等等都处理了,扔到哪里都工作。
下面是点击后弹出的效果:
更复杂的接口
上面的例子基本上解决了简单的列表式弹出窗口的情况,如果弹出来的东西比较复杂怎么办?比如我想把一个任务分配给我负责的组或我参与的组的某个组员,而且不希望这些组员直接按姓名排列(假设我记不住这些人),希望能呈现出一个下面这样的界面来:
图中点一下人名,就能把这个任务分配给这个人。
这个时候千万别先想技术实现手段,而是先要想一下:到底有几个业务信息要处理?其实就4个:
1. 哪个任务?任务的ID
2. 什么信息要改?“当前负责人”
3. 可选人员有哪些?“我的组(我负责管理的和我参与的)”
4. 设置好了要做点什么?“刷新一下屏幕”(主要是为了让更新后的内容接受一下Document.Ready里边的JS重新刷一下)
所以函数声明是:
item是那个任务
sdcTypeValue是之前定义好的自定义字段的值(不是为了这个AjaxValue定义的,SDC=System Defined Column系统自定义字段)
AjaxValue.ValuesKey是个enum稍微复杂一点。之前总是直接输入string[]来代表未来的值,现在有可能是User[]……等等,所以干脆传递一个enum由函数内部判断这次是找什么,里边再详细处理。
urlFormat哪去了?由于AjaxSDCValue是我们专门用来处理系统自定义字段的,所以urlFormat是统一的,请看函数内部:
实际上完全使用原来的函数AjaxValue也能实现,但是向用户暴露了过多的技术细节(尤其是形成urlFormat的式子太复杂),完全是用户不应该关心的。
/SFC/items/AjaxSetSDCValue会把Item的USER_CURRENT_OWNER字段设置为value的值。
弹出的复杂菜单哪来的?我们总结了一下,发现AjaxValue大致可能弹出以下几种东西:
1. 最基本的一串字符串(原来那个string[],可以处理可用的预估值、剩余时间值、花费时间值……)
2. 我的组的人员(分配任务、分配Bug、安排值班、安排休假……)
3. ……
urlFormat不同点击后的功能就不同,但上述菜单的结构和外观每次都相同。
所以就做了一个AjaxController.PopupAjaxValuesMenu,会根据传进来的AjaxValue.ValuesKey这个enum来判断弹出哪个菜单(包括准备菜单中的数据),顺便把urlFormat也传进去。
回顾
设计和调试这一堆东西还是花了2天时间的,但是从此再也不用见到大约每次都要50行左右的C#/Html代码了。
当未来的维护者看到这段代码时:
他会想:“哦,这里要把Story的CurrentOwner调整为……我的Team中的一个人,如果成功了会来刷新这条故事。而且,前面似乎还显示了个头像图标!”
这比面对50行漫天飞的代码要舒服多了。
写到最后,突然想起来10年前总结过的另一句话:
封装的最高境界,就是用和自然语言一样多的文字写完调用代码,剩下的全部隐匿起来。