前述讨论: TheBeerHouse 网站项目学习笔记(1)----换肤技术
TheBeerHouse 网站项目学习笔记(2)----个性化管理
TheBeerHouse 网站项目学习笔记(3)----安全管理(上)
TheBeerHouse 网站项目学习笔记(4)----安全管理(下)
摘要:TheBeerHouse整个网站是属于CMS(Content Management System)架构的系统,即基于内容的网站设计,这是网站设计最普遍的一种架构.在此网站的设计中,为什么需要用到许多抽象基类,为什么需要各种看似让人难以理解的属性和成员变量,设计意图是什么,这么设计有什么好处等等这类问题,都是值得我们思考和探讨的问题.我们将从层次关系、类图关系、设计意图这几个方面讨论上述提出的问题.
一. 层次关系
如上图,红色虚线框内的将是我们讨论的内容,这里面几乎全部是类,他们共同构成了我们新闻文章管理模块的功能架构.首先我们看到,这些类全部放到了App_Code目录中,在这个目录中包含了逻辑层和数据层的各种类,这些类各具功能,和我们以前学习的中规中矩的三层架是有很多区别的,以前的三层结构中分为实体层(Models)、数据层(ModelService)、逻辑层(ModelManager),这些层中只有简单的引用关系,基本不存在继承或实现接口的关系。那么当需求增加后,这些层次关系是可以实现扩充的,但总显得有些单调,因为有这么样一句话是说的非常有道理的:在实际设计中,类的设计对于一些相似的功能类总该保持一个或多个基类,保持基类短小,让它只包含子类所需的通用功能是个好的设计习惯, 即使最初在基类中不想放任何详细的代码,但以后如果需要一个通用属性和方法, 那么在整个架构中拥有一个基类也会很方便的.一般基类都设计成抽象类,所以我们在此结构中看到的抽象类几乎都是对下面具体子类通用功能的抽象。对于层次关系的讨论我们就从基类开始.
二. 逻辑层的结构
以下是逻辑层的类关系图:
其实CategoryDetails类是数据层的一个实体类,但它和逻辑层的类之间有些依赖关系, 所以在这里也画进来了。这些类的关系有别与一般的三层结构中的单纯
的类关系,因为这里引入了抽象基类的概念.下面逐个介绍这些类的用途,以及为什么要使用如此的设计方法。
1. BizObject 这是逻辑层的最顶层的基类,从此类是斜体就看得出,它是一个抽象类.许多业务对象需要访问很多共享信息,比如当前用户名/IP地址以及当前环境中Cache对象的引用.这些信息可以放在一个BizObject基类中,让其他所有域对象从它继承.该基类还可以包含一些辅助方法,如通过替换特殊字符(例如'<'及'>')来对HTML输入进行编码. 实际上,保持基类短小,让它只包含子类所需的通用功能是个好的设计习惯, 即使最初在基类中不想放任何详细的代码,但以后如果需要一个通用属性和方法,那么在整个架构中拥有一个基类也会很方便的.
我们看到,此类的各种方法和属性都是最基本的,都是新闻文章模块中所有类都需要的一些公共属性或字段以及方法,比如ConvertNullToEmptyString方法,其实这个方法代码非常简单,如果输入的字符串为Null,那么就转换为 " " 的字符串,这个小的方法是所有下面子类或孙子类都可能需要的一种方法,那么我们就将这个方法抽象出来作为通用基类的一个方法提供给子(孙)类来用。当然,这只是一个小小的"伎俩",但体现了基类的作用,以及面向抽象的意义,面向抽象这个概念会在数据层的关系图中得到详细体现,在下面再来介绍.其实这个类下面其它的方法和属性跟刚才介绍的这个方法一样,提供最一般的所有类的共享信息。当然这么做的作用就是想"代码复用".
2. BaseArticle 类是Article、Category和Comment的基类。它派生自BizObject类,并在此基础上添加了一些文章特定的属性。注意:这里是特定于文章的一些公共属性,所以这个类的抽象性较BizObject类要弱一些,也就是更接近底层一些,更具体一些。
以上ID,AddDate,AddBy三个属性对文章模块中所有的业务类都是通用的,所以它可以被Comment,Article,Category这些类所继承,这些就是基类存在的价值,也是我们在设计的时候需要周全考虑的因素,因为这样必然带来代码重用的效果,避免在以上三个类中都去添加ID,AddDate,AddBy这样的三个属性.
我们重点说明Settings这个属性:见如下代码和注释:
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
这个属性将返回一个ArticlesElement配置类的实例,那么这个属性到底有什么作用?我们知道,在整个网站的运行过程中都会有各种参数设置的,这些设置都可以通过前述TheBeerHouse 网站项目学习笔记(2)----个性化管理 中介绍的自定义配置节进行操作,那么我们就可以在网站运行期间动态的去读这些配置信息,比如"是否启用缓存","每页显示记录数","RSS阅读器的显示数目"等这些设置都可以运行时访问并修改,前句说的"运行时访问"操作大多集中在BaseArticle的三个子类上(Article,Category,Comment),因此,BaseArticle.Settings大多作在其子类中作为判断下一步行为的依据而存在.比如在Article类中有如下的判断语句:
if (BaseArticle.Settings.EnableCaching && BizObject.Cache[key] != null)
{
articles = (List<Article>)BizObject.Cache[key];
}
else ...............
以上的BaseArticle.Settings.EnableCaching就是在子类进行文章获取的时候先判读是否网站的"启用缓存" 开关开启,如果开启那么就到缓存中直接去取数据.
以上就是Setting属性存在的价值,那么还需要强调的就是此三个子类都需要这些开关,所以我们就把Setting属性做到了BaseArticle类中去,这么做当然是符合代码复用原则的.
以上是逻辑层类设计的意图和相互关系,其实我们在认真分析这些类的关系后,还应该多思考为什么作者要这么设计,这么设计对于系统弹性会带来哪些好处,这么设计我自己能否掌握,在今后的设计中如何借鉴或模仿。
那么下篇将继续介绍数据层设计的意图和类关系,并介绍些设计技巧...........