而面向接口编程可以使我们避免这种问题。我们不再依赖于千千万万个PartnerAccess或者什么别的Access类,而是依赖一个IDataAccess的接口。这样,所有的数据存取都被标准化,我们的调用代码便的更简单,不会依赖任何数据库的结构,甚至不需要知道表的名字,有多少个字段等等。当我们增加一个OrderAccess类时,只需在数据存取层增加一个文件,一个类好了,而不需要更改业务逻辑层的任何代码。
记住这个原则吧,它也可以说是面向对象的核心思想。会让你受益匪浅的!
3. 领域模型不清晰
从上面的图中可以看出来,本系统同时使用了两种领域模型,一种是业务对象(Business Object),一种是强类型DataSet(Strong Type DataSet),并且在每个层次中都使用了。
举个简单的例子:强类型DataSet被应用到ASP.NET的控件绑定上,用来显示数据。而业务对象被WebService暴露给客户端。
如果有人看过马丁·福勒的那本《企业架构模式》的话,应该会记得对领域模型的选择上有几种方案。其中业务对象和强类型DataSet都被提到了,并且说明了什么时候适用哪个模型。这里我不多说,感兴趣的朋友可以去看看那本书。
我想说的是,这里使用了两个模型并存的方案。这样使得系统的领域模型不清晰,而且存在很多的冗余,例如出现了Partner业务对象和PartnerDS强类型DataSet并存的现象,尽管他们各有各的优缺点,但这样势必会造成领域模型的难于维护和代码可读性差的问题。
其实,特殊情况下,也可以两个同时使用,但要注意,由于业务对象是属于业务逻辑层的,而强类型DataSet是数据存取层的,所以他们都要在自己的范围内活动,不能被其它的层次存取。
到这里,有人可能会发现一个矛盾是:使用单一业务对象的话,则会对数据存取层带来额外的开销,因为数据存取层不能知道业务对象的存在,需要使用抽象,会带来一些代价。但如果使用单一的强类型DataSet的话,会对业务逻辑层和展现层保留很多的内部数据细节,也会对系统架构造成一些影响,而且也不利于WebService的传输。
其实,一个合格的设计师,需要对这两种方案做各自的调整,都为自己所用,但只取他们的优势,而避免他们的劣势多带来的麻烦。
软件设计,何尝又不是一种取舍的艺术呢!
4. 强类型DataSet
上面讲到了业务对象和强类型DataSet两种领域模型的使用问题。其实强类型DataSet是.NET中很好的一种方案,它集成了数据库和面向对象两种优点,如果使用的好的话,会事半功倍,但使用不好的话,麻烦也很大。
在本系统中,强类型DataSet被赋予很多使命:从数据库中获取信息(数据存取层)、业务处理(业务逻辑层)和数据展现(展现层),贯穿了整个系统。这样使得整个系统对强类型DataSet的数据结构非常依赖,一旦数据库发生变化,所有的代码(从数据存取到展现层)都要修改代码来。并且要命的是强类型DataSet可以自动感知数据库的变化,自动更新同步。试想,如果你是这个系统的编码人员,会不会时时都提心吊胆呢?
很显然,这是一种糟糕的设计。在分层结构中,任何数据结构都不能贯穿始终,特别是与数据库结构。这回带来难以置信的麻烦。分层,其实是要隔离这种变化给系统带来的连锁反应。使底层的修改不影响到顶层,反之亦然。
当然这是不是意味着强类型DataSet不能使用了呢?当然不是的。强类型DataSet是非常好的连接数据存取层和业务逻辑层的纽带,因为它既有数据库结构又有对象特性。所以,只要我们能在两个层次中各自屏蔽细节,依赖于抽象而不是实现,强类型DataSet可以在系统中发挥重要的作用。
5. 展现层太臃肿
本系统的很大一部分UI都是B/S的,采用ASP.NET构建。但我发现很多的WebPage中包含有大量的界面逻辑和业务逻辑,基本每个WebPage的代码都在几百行,有点甚至上千行。试想,这样的UI维护起来…
对于每一个开发者来说,大概都经历过这种痛苦,为了数据库的一个字段的修改,要从底层到顶层,全部修改一便,而且UI的修改是麻烦的,往往是越改越烦!
其实对于UI的设计模式已经很成熟了,大家都知道MVC模式吧。是一个很成熟,很实用的UI设计模式。另外还有MVP模式,这个是MVC的基础之上提出来的,跟MVC思想相同,但细节上有所不同而已。MVC模式网上有很多的资料,也有很多有名的应用案例。MVP则被广泛应用在微软P&P团队的很多项目中,诸如:Software Factory系列中都有应用。
下面是MVC模式和MVP模式的对比:
另外,关于两种模式的详细对比,可以参考另一位MVP:TreeLee的文章:ASP.NET MVC Framework与WCSF中MVP模式之小小比较。