非业务方面的改动不会影响到其他地方。
有人应该注意到了图中的配置文件。在没有它的时候,业务层是依赖于业务数据访问层的,细心的读者应该能从业务层与业务数据访问层关系图中发现这个问题。这样双向依赖的关系是以后造成无法复用的根本所在。因此需要抽象出业务数据访问接口,让业务层去依赖这个接口,而不是业务数据访问层。但光声明接口是不够的,因为在实例化的时候仍然需要具体的下层类,所以依旧无法摆脱依赖关系。于是把依赖转移出来,这又引出了依赖倒置(Dependency Inversion Principle)的概念,具体可以参见Martin Fowler的相关论述。IoC(Inversion of Control)容器为我们提供了完美的方案,通过它将不同的模块注入到系统中我们可以在不知道这个组件存在的情况下调用它。这样的方式同样适合于权限管理,邮件发送等等其他组件。Spring.Net和Castle是dotNet下的两个优秀的IoC容器Spring.Net是
Java下Spring的移植版本,Castle相对更要成熟。但是当你使用的组件并不是很多而不愿使用配置这些复杂而强大的产品时,你就要手工完成这些工作,你需要把业务层使用那些数据访问组件写在配置文件中,然后通过工厂(Factory)解析配置文件应用反射(Reflection)技术实例化出你的组件。
最后再说点关于AOP(Aspect-OrientedProgramming)的话题,在一些非常通用的组件或者系统功能间我们可以使用AOP技术来打散系统其他部分对他们的依赖。像权限管理,系统日志,异常处理等。拿权限管理来举例,通常我们是在需要做权限检测的函数内部的开头来加一行权限检测代码,通过则执行后续代码否则跳出。这样写破坏了业务的纯洁性,业务的存在于权限并没有什么关系,而且使业务代码依赖权限组件,当我需要去除权限而另做新
系统的时候这是见很麻烦的事情。AOP的好处在于可以以声明方式来处理这些问题,例如你只需在需要验证的函数前加上一行属性的描述或者在配置文件中写上那些函数需要验证,执行时AOP组件会按照你预先定制的先后顺序执行你的代码,这样我们可以轻松的剥离这些组件而丝毫不会对现有系统造成任何影响。
关于Service层的讨论
Service层是一个构建于表示层于业务层之间的层,它是对业务层的一个浅封装而不应该封装过多的业务逻辑,否则会造成不必要的麻烦。然而它并不是任何时候都有必要存在。一种情况下当你的UI所要展现的东西和你的业务实体并不是那么完全吻合的时候,例如你的界面需要显示若干个业务实体的一部分,但这并不是业务本身,只是一种展现方式。这时候你需要Service层来做一个展现逻辑的转换。或者当你在做分布式系统的时候可以利用Service层来实现一个粗粒度的服务接口。也可以以SOA(Service-oriented Architecture)的方式来理解Service层,我们最终使用的是系统所提供的服务而不是业务对象,所以需要将将业务对象以清晰的方式组织起来形成清晰的服务暴露在外。更多的情况在于你结合实际该如何使用。
结束语
至此,整个架构方案的讨论已经完成,我们可以看出dotNet下可供选择的解决方案是那么的有限,反看Java世界,有那么多成熟可供利用的组件框架,甚是着急。不过dotNet也正在走向成熟,我们需要时间等待。以上提供的方案仅代表了一种基本的思路,在具体环境中需要做具体的调整。希望能起到一个抛砖引玉的作用。我的联系方式见Blog,由于经验不足,有不正确的地方欢迎指正讨论。