小议传统分层与新式分层,抑或与DDD分层

引言

本文提到的分层只是软件架构上的分层。文中的传统分层指的是传统的三层结构:UI(界面表现层),BLL(业务逻辑层),DAL(数据访问层)。文中提出的观点也都是个人的一点认识,与任何组织没有关系,如有异议,还请各位踊跃拍砖。

当然了,出现的这些问题,也可能只是我个人的问题,不代表每个人都存在。无则加勉,有则改正吧。如果是个人的问题,那就当是个人总结吧,大家看看就算了。

这里说到的传统分层,也有可能是我对于分层的错误理解造成的,但是我看见的不只是我的项目是这么的结构,很多的项目也都是这样的结构。里面的代码, 都和我理解的一样,至少可以说明,还是有一部分人犯了和我一样的错误。

 

传统分层

 

传统分层最大的问题就在于割裂了上层与下层之间的联系,把他们之间的关系变成了简单的接口调用,变成了完全的接口形式主义。同时,忽略了下层是为上层提供服务的,不是单独存在的,下层提供的服务应该受到上层的规约。当然,也不是说不可以提供更多的服务,但是至少应该提供上层需要的,然后再考虑提供一些“边角料”。

我们先看一个传统分层的解决方案结构。

image

相互之间的引用关系是:UI引用BLL、Entity、Common;BLL引用IDAL、Entity、Common;IDAL引用Entity;DAL引用IDAL、Entity、Common。

显示行号 复制代码 UI  Code
  1. private void button1_Click(object sender, EventArgs e)
    
  2.        {
    
  3.            _02_BLL.OrderBll orderBll = Common.ServiceLocator.LoadService<_02_BLL.OrderBll>();
    
  4.            orderBll.SubmitOrder(new _05_Entity.OrderEntity()
    
  5.            {
    
  6.                OrderSeqNo = "123",
    
  7.                OrderAmount = 1000
    
  8.            }); 
    
  9.        }
    
显示行号 复制代码 BLL Code
  1. public class OrderBll
    
  2.    {
    
  3.        IOrderDal _orderDal;
    
  4.        public OrderBll()
    
  5.        {
    
  6.            _orderDal = Common.ServiceLocator.LoadService<_03_IDAL.IOrderDal>();
    
  7.        }
    
  8.        public bool SubmitOrder(OrderEntity order)
    
  9.        {
    
  10.            return _orderDal.Add(order);
    
  11.        }
    
  12.    }
    

 

显示行号 复制代码 IDAL Code
  1. public interface IOrderDal
    
  2.     {
    
  3.         bool Add(OrderEntity order);
    
  4.     }
    

 

显示行号 复制代码 DAL Code
  1. public class OrderDal:_03_IDAL.IOrderDal 
    
  2.    {
    
  3.  
  4.        public bool Add(_05_Entity.OrderEntity order)
    
  5.        {
    
  6.            IDbConnection conn = new SqlConnection();
    
  7.            conn.Open();
    
  8.            IDbCommand comm = conn.CreateCommand();
    
  9.            IDbDataParameter param = comm.CreateParameter();
    
  10.            param.Direction = ParameterDirection.Input;
    
  11.            param.DbType = DbType.String;
    
  12.            param.ParameterName = "OrderSeqNo";
    
  13.  
  14.            if (comm.ExecuteNonQuery() > 0)
    
  15.                return true;
    
  16.            else
    
  17.                return false;
    
  18.        }
    
  19.    }
    
显示行号 复制代码 Unity Container Locator
  1. using System.Configuration;
    
  2. using System.Globalization;
    
  3. using Microsoft.Practices.Unity;
    
  4. using Microsoft.Practices.Unity.Configuration;
    
  5. using Microsoft.Practices.Unity.InterceptionExtension;
    
  6. using System.Web;
    
  7. using System;
    
  8.  
  9. namespace Common
    
  10. {
    
  11.     public static class ServiceLocator
    
  12.     {
    
  13.         // private static readonly InterfaceInterceptor  injector = new InterfaceInterceptor ();
    
  14. 
    
  15.         private static readonly TransparentProxyInterceptor injector = new TransparentProxyInterceptor();
    
  16.  
  17.         public static IUnityContainer Container
    
  18.         {
    
  19.             get;
    
  20.             private set;
    
  21.         }
    
  22.         static ServiceLocator()
    
  23.         {
    
  24.             Container = new UnityContainer();
    
  25.             UnityConfigurationSection unitySection = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
    
  26.             if (unitySection == null)
    
  27.             {
    
  28.                 throw new ConfigurationErrorsException(string.Format(CultureInfo.CurrentCulture, "missing unity configuration section"));
    
  29.             }
    
  30.             Container.AddNewExtension<Interception>();
    
  31.  
  32.             unitySection.Configure(Container, "Container");
    
  33.  
  34.         }
    
  35.         /// <summary>
    
  36.         /// 没?有D为a映3射?指?定¨别e名?
    
  37.         /// name属?性?没?有D赋3值μ
    
  38.         /// </summary>
    
  39.         /// <typeparam name="T"></typeparam>
    
  40.         /// <returns></returns>
    
  41.         public static T LoadService<T>()
    
  42.         {
    
  43.             Container.Configure<Interception>().SetDefaultInterceptorFor<T>(injector);
    
  44.             return Container.Resolve<T>();
    
  45.         }
    
  46.         /// <summary>
    
  47.         /// 为a映3射?指?定¨别e名?
    
  48.         /// name属?性?赋3值μ
    
  49.         /// </summary>
    
  50.         /// <typeparam name="T"></typeparam>
    
  51.         /// <param name="serviceName"></param>
    
  52.         /// <returns></returns>
    
  53.         public static T LoadService<T>(string serviceName)
    
  54.         {
    
  55.             Container.Configure<Interception>().SetDefaultInterceptorFor<T>(injector);
    
  56.             return Container.Resolve<T>(serviceName);
    
  57.         }
    
  58.     }
    
  59. }
    
  60.  

 

上层在调用下层的时候,不是调用自己需要的,而是从下层提供的服务中筛选一些可以用的,凑合用一下。如果发现没有自己可以用的,就在IDAL文件中添加一个,然后在DAL文件中实现以下,这下好了,BLL可以用了。这样也会造成在开发DAL层的时候,没有充分考虑BLL的需要,自己盲目实现一些,然后BLL用的时候,才发现很多还要重新写。造成大量的浪费,代码、人力、时间、精力都浪费一部分了。也会影响到开发的进度。

 

新式分层,抑或叫做DDD分层

 

说是新式分层,其实也是我随便叫的。就是这段时间看了博客园的一些DDD文章,还有就是codeplex上的两个项目NLayerApp和SmartCA的源码。看了这些之后,有的一点理解。不管是神似还是形似吧,反正觉得比以前传统分层有一点道理,就分享出来了,也挣点人气,骗点点击量,哈哈。

先来一张图吧。

image

DDD中的分层主要是四层:Presentation(表现层),Application(应用层),Domain(领域层),Infrastructure(基础层)。

Presentation相当于以前的UI层。Application是一个任务的调度层,没有实际的业务逻辑,也不推荐放入业务逻辑,实际中可以用Wcf来代替,或者使用普通的类库就可以。其实就是根据UI的业务调用,然后映射到具体的领域对象身上去。也可以通过Application来暴露粗粒度的业务处理,因为领域层的业务处理是细粒度的。没有了以前的DAL,把它的部分放入了Infrastructure层。

以前的IDAL被放入了Domain,在图上,是Domain.Core项目,这个项目会被Infrastructure引用。因为Domain.Core中的IDAL相当于是领域对象对于持久化提出的要求,也就是说必须要实现这些功能,这些都是领域对象需要的。具体的如何实现,具体如何持久化,是持久化到关系数据库还是文件系统,还是内存数据库,都由具体的实现来定义。也就是图中的Infrastructure.Data.Core和Infrastructure.Data.MainModule项目。这两个项目中的实现,实现的都是领域对象持久化所需要的,不会实现一大丢不必要的方法。不知道这算不算是改进呢?

 

结论

传统分层,或者说是我理解的传统分层,存在的问题就是割裂层之间的联系,形式化了层之间的联系。没有表达出上层对于下层的需要,下层是为上层服务的,这些联系。DDD的分层可以解决这个问题,会提高开发的效率,少走一些弯路。

不知道大家是如何认识的呢????????期待大家的回复,拍砖。

转载于:https://www.cnblogs.com/virusswb/archive/2011/01/10/1931964.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/422954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【OS学习笔记】三十九 保护模式十:中断和异常的处理与抢占式多任务对应的汇编代码----动态加载的用户程序/任务一代码

本文是以下几篇文章对应的动态加载的用户程序/任务一代码&#xff1a; 【OS学习笔记】三十四 保护模式十&#xff1a;中断和异常区别【OS学习笔记】三十五 保护模式十&#xff1a;中断描述符表、中断门和陷阱门【OS学习笔记】三十六 保护模式十&#xff1a;通过中断发起任务切…

WCF 第八章 安全 客户端认证

一个服务的客户端认证是通过向服务提供一系列信赖的声明。声明可以是任何形式&#xff0c;只要客户端和服务端理解这个格式并信赖它的来源就可以。 如果客户端和服务端共享一个秘密信息&#xff0c;比如一个用户名和密码&#xff0c;只要客户端通过一个合法认证发送数据&#x…

前端学习(205):animation动画库

动画库 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible" conte…

【OS学习笔记】四十 保护模式十:中断和异常的处理与抢占式多任务对应的汇编代码----动态加载的用户程序/任务二代码

本文是以下几篇文章对应的微型动态加载的用户程序/任务二代码&#xff1a; 【OS学习笔记】三十四 保护模式十&#xff1a;中断和异常区别【OS学习笔记】三十五 保护模式十&#xff1a;中断描述符表、中断门和陷阱门【OS学习笔记】三十六 保护模式十&#xff1a;通过中断发起任…

JS调用后台方法大全

javascript函数中执行C#代码中的函数&#xff1a;方法一&#xff1a; 1、首先建立一个按钮&#xff0c;在后台将调用或处理的内容写入button_click中;    2、在前台写一个js函数&#xff0c;内容为document.getElementById("btn1").click();    3、在前台或后…

【OS修炼指南目录】----《X86汇编语言-从实模式到保护模式》读书笔记目录表

学习交流加&#xff08;可免费帮忙下载CSDN资源&#xff09;&#xff1a;个人微信&#xff1a; liu1126137994学习交流资源分享qq群1&#xff08;已满&#xff09;&#xff1a; 962535112学习交流资源分享qq群2&#xff1a; 780902027 本文是将个人的关于《X86汇编语言-从实模式…

C语言编译全过程剖析

内容摘要 C语言编译的整个过程是非常复杂的&#xff0c;里面涉及到的编译器知识、硬件知识、工具链知识都是非常多的&#xff0c;深入了解整个编译过程对工程师理解应用程序的编写是有很大帮助的&#xff0c;希望大家可以多了解一些&#xff0c;在遇到问题时多思考、多实践。 一…

【剑指offer - C++/Java】7、斐波那契数列

在线题目链接&#xff1a;斐波那契数列 文章目录1、题目描述2、题目分析3、代码3.1 递归方法3.11 Java代码3.12 C代码3.2 动态规划3.21 Java代码3.22 C代码3.3 循环方法3.31 Java代码3.32 C代码4、总结1、题目描述 大家都知道斐波那契数列&#xff0c;现在要求输入一个整数n&a…

母版事件中注册javascript脚本

母版事件中注册javascript脚本 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆ Title :㈠母版等事件中注册javascript脚本 Description: version : 1.0 Date :8:46 2008-3-26 Author : Tia…

【剑指offer - C++/Java】8、跳台阶

在线题目链接&#xff1a;跳台阶 文章目录1、题目描述2、题目分析3、代码3.1 递归方法3.11 Java代码3.12 C代码3.2 动态规划3.21 Java代码3.22 C代码3.3 循环方法3.31 Java代码3.32 C代码4、总结1、题目描述 一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级。求该青蛙跳…

【剑指offer - C++/Java】9、变态跳台阶

题目链接&#xff1a;变态跳台阶 文章目录1 题目描述2 题目分析3 代码3.1 动态规划算法3.11 Java代码3.12 C代码3.2 递归算法3.21 Java代码3.22 C代码3.3 直接求解 公式&#xff1a;f(n)2^(n-1)^3.31 Java代码3.32 C代码4 总结1 题目描述 一只青蛙一次可以跳上1级台阶&#xf…

在Linux上构建ASP.NET环境-asp.net关注

在Linux上安装mono,xsp,mod_mono后&#xff0c;可以构建一个ASP.NET环境&#xff0c;Mono项目是由Novell支持的。mono官网地址&#xff1a;mono下载页面&#xff1a;/mono-downloads/download.htmlXSP是一个轻量级的Web服务器&#xff0c;它是用100%的C#代码写成的纯.Net应用程…

【剑指offer - C++/Java】10、矩形覆盖

在线题目链接&#xff1a;矩形覆盖 文章目录1 题目描述2 题目分析3 代码3.1 递归方法3.11 Java代码3.12 C代码3.2 动态规划算法3.2 动态规划3.21 Java代码3.22 C代码3.3 循环方法3.31 Java代码3.32 C代码4、总结1 题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形…

C++ primer 笔记(二)

第9章 sequential container 顺序容器: vector 快速随机访问 list快速插入删除 deque双端&#xff0c;随机访问 C<T> c; C c(c2); C c(b,e); //迭代器,数组,指针&#xff0c;不要求两个容器类型相同 C<T> c(n,t); //只适用与顺序容器 C<T> c(n…

【剑指offer - C++/Java】11、二进制中1的个数

在线题目链接&#xff1a;二进制中1的个数 文章目录1 题目描述2 题目分析2.1 方法12.11 Java代码2.12 C代码2.2 方法22.21 Java代码2.22 C代码3 总结1 题目描述 输入一个整数&#xff0c;输出该数二进制表示中1的个数。其中负数用补码表示。 2 题目分析 2.1 方法1 这道题看起…

IIS 启动不了(服务没有及时响应启动或控制请求)解决

以前用360时为了加快开机速度,经常禁用一些服务, 就是这样 Eventlog WorldWideWebPublishing Remote Procedure Call IIS Admin Service 把这些服务都启动了就能启动iis网站了转载于:https://www.cnblogs.com/x4646/articles/1948780.html

【剑指offer - C++/Java】12、数值的整数次方

在线题目链接&#xff1a;数值的整数次方 文章目录1 题目描述2 题目分析2.1 方法1 循环2.11 Java代码2.12 C代码2.2 方法2 递归2.21 Java代码2.22 C代码3 总结1 题目描述 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 2 题目分析 2.1 方…

ASP.NET四种页面导航方式之比较与选择

在ASP.NET应用中&#xff0c;Web表单之间的导航有多种方式&#xff1a;用超级链接&#xff0c;用Response.Redirect&#xff0c;用Server.Transfer&#xff0c;或者用Server.Execute。本文将分析这四种导航方式的异同及其优缺点&#xff0c;帮助你选择最佳的导航方式。 一、超级…

【剑指offer - C++/Java】13、调整数组顺序使奇数位于偶数前面

在线题目链接&#xff1a;调整数组顺序使奇数位于偶数前面 文章目录1 题目描述2 题目分析2.1 方法12.11 Java代码2.12 C代码2.2 方法22.21 Java代码2.22 C代码3 总结1 题目描述 输入一个整数数组&#xff0c;实现一个函数来调整该数组中数字的顺序&#xff0c;使得所有的奇数位…

Camparable与Comparator之区别

一个类实现了Camparable接口则表明这个类的对象之间是可以相互比较的&#xff0c;这个类对象组成的集合就可以直接使用sort方法排序。 Comparator可以看成一种算法的实现&#xff0c;将算法和数据分离&#xff0c;Comparator也可以在下面两种环境下使用&#xff1a; 1、类的设计…