讨论完了语言又讨论培训,讨论完了培训又讨论分层,这些话题似乎永远都讨论不完。讨论总是有益的,但是如果讨论的命题本身就有问题的话,可能副作用就比益处来的更大了。
三层 = 表现层+业务逻辑层+数据访问层 ?
是不是所有系统一定要分成三层,是不是所有三层的系统都一定是这三层,如果我写一个不需要数据存储的应用呢,如果我写一个没有界面的程序(库)呢?
为什么一提到三层就是这三层?因为所有的讨论都是基于“中小型b/s或c/s应用系统",因为这样的系统现在最常见,也是做的最多的。但是我们不能仅仅将眼光局限在这个领域里,而是应该放的更长远,分层是一个普遍使用的概念,不能仅仅局限于“三”层,也不能仅仅局限于"UI+BL+DAL"。三层只是分层的一个特例,UI+BL+DAL的组合也只是三层系统的一个特例,理解了特例不代表理解了分层;而理解了分层自然就能理解这个特例了。因此请不要在讨论三层了,直接讨论分层吧,这样可以少一些误解,少一些争论。例如,那些说三层(UI+BL+DAL)不好的人,不会因此而否定分层,他仍然可以分两层或者一层,而不是拒绝分层;讨论也会仅仅限于此三层是否好用,是应该改变之中的某一层还是改变层次的数目,什么时候应该分三层,什么时候应该分两层。
再来说说分层的优缺点,任何东西都不是完美的,它只能解决某些特定的问题。解决不了所有的问题不是它的错,使用它来解决它不善于解决的问题绝对是你的错。
我喜欢分层的原因是:分层可以将底层操作包装,使你在任何一层工作时,可以只考虑下面的一层,而无需考虑更下面的所有层的细节,甚至是一共有多少层。这是一个抽象的机制,这是一个名字的集合,你会使用”GetAllUsers"而不是"select * from users order by id"来思考问题,你会使用"获取购物清单”而不是“拿到一张写满了我所买商品以及他们价钱的列表”,如果没有分层可能你在写代码的时候还要考虑某个电子是如何将内存中的一个二进制位设置成“1"。 我曾经遇到过一个系统,这个系统很小,大概也就几千行代码,它使用VB来访问一个.ini的配置文件、一个数据库和一个execl模版。它的主要功能就是根据.ini的配置信息,从数据库中获取某些数据,放到模版的某个cell中。代码虽短但是非常难懂,它每执行一个操作都要调用几乎相同的3-5行代码来读取.ini文件,这些代码唯一不同的地方就是要读取的键值,以及返回结果的类型(强制类型转换)。看到这里大家应该很容易看出来,只要提取一个函数就行了。是的,仅仅是提取一个函数,就使得代码的清晰程度大幅增加,同时减少了重复代码。这个函数其实就是一个“数据访问层”,它将对.ini文件的访问细节包装起来,任何使用它的代码都无需知道实现细节,只要知道调用这个“GetValueFromConfig(key)”就可以得到自己想要的东西。这样,你就摆脱了每次考虑如何访问配置文件的细节,可以专注于更高层的逻辑了。这里顺便说一下,很多人认为“数据访问层”的作用是可以替换数据库,实际上这种情况在框架以外的程序中并不经常发生。在应用程序中,将对数据的访问抽象出来才是更常见的动机。
当然就像前面说的,分层也有它自己的问题:首先是级联修改,典型的例子是在网站中需要添加显示一个字段,就需要修改每一个层。 另一个问题是性能,层次越多性能受到的影响就越大。不过这些缺点不是你不用分层的理由。级联修改可能是由于没有定义好层次间的接口造成的,也可能是需求变更造成的。如果是正常的需求变更,造成级联修改的次数是有限的,并不会盖过分层所带来的好处;如果级联修改过于频繁,则可能是需求太不稳定或者架构设计有问题。至于性能问题,现在计算机的速度越来越快了,系统的瓶颈通常都在磁盘IO或者网络传输,分层造成的CPU和内存消耗在绝大多数系统中不是主要问题,因此除非是资源有限且性能要求很高的程序,一般来说这也不是一个问题。
那么分多少层合适,每层的职责又是什么?
分多少层取决于应用的复杂度以及特点,如果你的系统本身不复杂而又分了很多的层,必然有些层中没什么逻辑,那么这些简单的层所带来的烦恼就要大于好处了; 如果分的层过少,就会在一个层中混杂不同抽象程度的概念,使你的思维总在高层于底层之间跳跃,造成逻辑的代码的混乱。分层没有规范,任何分层系统都要在实践中接受考验,三层是一个好的开始,但并不是终结,当你觉得三层不合适的时候,改变吧,相信你的直觉,而不是某些所谓的“权威”说的“三层好,一定要用,两层是邪恶的,sp是邪恶的……”。或许有一天你会同意三层确实比两层好,但是在你还不知道为什么三层好的时候,乖乖的使用两层(或者其他什么你认为好的东西),远远比懵懵懂懂的误用三层,然后误解三层,最后远离三层要好的多。