微软的IDE奇妙之处就是在于其能够一直秉承“快速开发”的理念——对于一个初学者而言,通过简单的拖拉控件,以及各种对应的触发事件中写写画画就能开发出一个像模像样的程序来,实在是增强了他们的自信,和进一步研究、从事开发软件的兴趣。
不过毕竟“金无赤足,人无完人”——微软这种快速开发理念会带来一个非常严重的问题——界面和代码逻辑上混合在一起,以至于修改界面要牵涉到代码的移动,真所谓“牵一发动全身”。虽说微软不断强调“界面和代码是分离的”,但就我看来,这种“分离”也无非是一种形式上的分离罢了——你想想,为什么“分离”的类文件可以和UI的某个控件相互关联起到作用?说穿了不就是“委托”(一般和事件连用,动态调用不同类中“同名、同参、同返回类型”的函数)在“牵线搭桥”么?所以一旦界面更改,我们就不得不冒着这样的危险,真是“打断骨还连着筋”:
1)删除一个控件——对应的委托自动被删除,这样先前这个委托所要调用的方法成了摆设,不仅空间浪费,恐怕程序员也要起误会的(这个方法干什么的啊?)。
2)更改一个控件——这有点看运气,如果被修改的控件和修改前的控件事件都是“同名、同参、同返回类型”的函数,那么你唯一要做的只是修改初始化文件控件事件的加载“挂接”部分(类似于“button.OnClick+=new EventHandler(XXXX)”中斜体部分),但只要“同名、同参、同返回类型”中一个与原来的不相同,你不得不重新寻找新控件的事件,然后“Ctrl+C,Ctrl+V”机械式粘贴原来的代码……变更的地方越多,你的痛苦便随之增加,正如数学中的正比例函数一样。
怎么办呢?原理上最好是做到“界面和代码完全分离”,这个显然违背了微软的IDE设计本意,所以我们只得另寻它法——终于觅得一个“两全其美”的方案,将逻辑代码写在自己创建的一个类(与窗体生成的类毫无关系)。然后只是在窗体的按钮事件中调用即可。后来这一思路越来越发达,终于形成了规范,在信息平台(诸如和数据库相关的程序)类程序中尤为突出明显——“界面层+业务层+数据操作访问层”就是著名的“三层结构”程序设计框架思想,这个思想影响了许多程序员和高级、乃至世界级的专家学者们,以至于后发的“SSH”、“ASP.NET MVC”和“ADO.NET”等技术都从它衍生而来,尽管模样千变万化,但我们不得不承认一点——那就是它们还都流淌者“界面和代码分离”的血液。
说到这里,正题研究便可以开始了——所谓“三层结构”,就是将“界面”和“代码”做到“完全”分离(“完全”的确“完全”可以达到,不过UI中不调用方法,似乎这个UI被架空了,成了“光棍司令”,毫无实际意义),便于界面设计者和程序员“各自为政,各尽其责”,同时也便于维护程序。下面就来解剖下“三层”的结构,以及和UI的关系吧。
l “三层结构”的模型和作用:
通常牵涉到数据库操作的信息平台使用到的三层结构大致结构如下:
当一个用户在一个界面上(无论是WinForm的还是WebForm形式),点击一个按钮或是一个超链接的时候,它必然会触发一个事件,此时它应该把用户所要求的任务“转换”成某种数据格式(可能是一个普通数据类型,或者是一个封装的类、结构等自定义数据结构),向它的“逻辑层”发送数据。
“逻辑层”是一种特殊的层,它的作用主要负责数据接受,效验数据的正确性并调用“数据操作(访问)层”对应的方法,起到一个类似于“控制器”的作用;同时也肩负着数据异常等其它零散的事务处理)。因此“逻辑层”的函数和参数列表应该和“数据操作(访问)层”中的方法一一对应。
至于“数据操作(访问)层”的代码主要任务是根据预订的目标任务,将每个表所要涉及到的操作封装起来,以便上层调用(一般包括“增、删、改和查”四项)。所以这些类往往需要直接和数据库打交道(包括数据库连接、打开等“底层”功能全在里边)。有时为了使得系统结构更清楚明了,往往将涉及到与数据库的底层操作再次封装成一个通用的“数据库操作”类,那么对于“数据操作(访问)层”而言,只要直接从那儿获取一个已有的连接,然后再次基础上进行操作就可以了。
为了程序编写的方便,一般.NET中有这样的“潜规则”:
1)界面层(缩写UI):为User Interface的缩写,直接与用户交互,即用户看到,能够操作的最终界面。
2)逻辑层(缩写BLL):为Business Logics Layer的缩写,负责接受传递的参数判断参数的合法性等,并调用对应的方法完成某项功能,并返回结果,报告呈现给UI层上供用户参考。
3)数据操作(访问)层(缩写DAL):为Data Access Layer的缩写,一般根据任务分析寻找不同数据表应有的对外功能,直接和底层数据库(表)打交道的层。
4)通用数据连接层(缩写DBUitl):为DataBase Utility的缩写,如果考虑数据库频繁打开或关闭容易出错,或为节省空间考虑,可以将数据源连接等直接写在一个通用的类中,以便今后直接被DAL调用,在此基础上操作即可。