一起谈.NET技术,走向ASP.NET架构设计——第四章:业务层分层架构(前篇)

简介:   在讨论完四种模式之后,我将会和大家一起来看看DDD的一些知识。每种模式的讲解,我都会用实例的形式给出完整的代码,也希望大家多琢磨!  不是所有的应用程序都是一样的,也不是所有的系统都需要用复杂的架构来组织业务逻辑。

  在讨论完四种模式之后,我将会和大家一起来看看DDD的一些知识。每种模式的讲解,我都会用实例的形式给出完整的代码,也希望大家多琢磨!

  不是所有的应用程序都是一样的,也不是所有的系统都需要用复杂的架构来组织业务逻辑。作为开发人员,我们必须清楚每一种业务逻辑组织的模式,这样我们才能在需要的时候做出合适的选择。

  Transaction Script

  这种组织业务逻辑的模式是最简单,也是最容易理解的。Transaction Script模式就是用面向过程的方式来组织业务逻辑的。通常情况下,系统的一个流程就被实现为一个方法,然后把所有的这些方法组织在一起,放在一个静态的manager类或者service 类中。实现流程的那个方法包含了业务逻辑的Check和Validation,数据的持久化以及其他的一些相关操作。也就是说,一个方法把所有的事情都做完了。当然,有时候这个大的方法还可能被拆成小的方法,便于重用。如下图所示:

  Transaction Script一个好处就是理解起来很简单,尤其是当Team中的一个新成员来说,更是如此,因为他几乎不用花什么时间,就能立刻明白这种组织业务逻辑的方式。每当来了一个新的需求的时候,要做的事情就是去加上一个或者一些新的方法来是实现这个需求,而其还不会影响其他已经存在的功能。

  对于一个很小的或者基本山没什么业务逻辑的系统来说,用Transaction Script模式组织业务逻辑还是很不错的,而且对一个刚刚踏入IT的开发人员门槛也比较低。:当系统开始变大,业务逻辑开始变得复杂的时候Transaction Script的问题的出来了。最后的结果可能就是系统中存在大量的方法,而且这些方法中到处都是重复的代码。有的时候,我们可以提炼出一些业务逻辑的验证代码组织为方法,但是我们去很难提炼出一些在流程上相识的代码,即使两个流程只有一点点的不同。如果系统的需求稍微一边,导致流程变了一点点,那么很多的方法就要改动,而且我们还得在系统中去找出那些相似的流程代码,然后修改,万一哪个方法没有找出,后果可想而知。

  下面我们就用一个人事请假管理系统为例子来看看Transaction Script是如何实现的。因为Transaction Script很简单,所以下面的代码也只是用于演示,大家理解就行了。

  
  
public class HolidayService
{
public static bool BookHolidayFor( int employeeId, DateTime From, DateTime To)
{
bool booked = false ;
TimeSpan numberOfDaysRequestedForHoliday
= To - From;
if (numberOfDaysRequestedForHoliday.Days > 0 )
{
if (RequestHolidayDoesNotClashWithExistingHoliday(employeeId, From, To))
{
int holidayAvailable = GetHolidayRemainingFor(employeeId);
if (holidayAvailable >= numberOfDaysRequestedForHoliday.Days)
{
SubmitHolidayBookingFor(employeeId, From, To);
booked
= true ;
}
}
}
return booked;
}

private static int GetHolidayRemainingFor( int employeeId)
{
// ...
}

public static List < EmployeeDTO > GetAllEmployeesOnLeaveBetween(
DateTime From, DateTime To)
{
// ...
}

public static List < EmployeeDTO > GetAllEmployeesWithHolidayRemaining()
{
// ...
}
}

  一眼看上去,我们就很容易理解这种面向过程的方式:系统中的所有的用例都被组织成了一个个的方法。例如在BookHolidayFor方法中就做了很多的事情:查询和持久化数据,是否允许请教的业务逻辑的实现等。

  如果在一个很简单的,业务很少的系统中采用这种方式还是可以的,随着业务逻辑的越来越复杂,我们就得重新考虑下这种组织逻辑的方式,越早发现,越早做出改变,以后的成本将会越小。

  Active Record

  当我们系统中的业务类和数据库中的表存在一 一对应关系的时候,尤其是每一个业务对象都代表了数据表中的一行,并且业务对象还要包含一些CRUD方法的时候,Active Record模式是比较合适的。下面我们来看看一个Blog系统例子:Post:就表示发表的一篇文章,Comment:评论。

  在Active Record模式中,每一个业务对象各自负责自己的数据持久化逻辑和相关的业务逻辑。正如前面提到的:Active Record模式很适合那种“业务对象和数据表一 一对应”的简单的应用程序,例如Blog,Forum等系统。因为在Active Record模式中,每一个业务类和表都有对应的关系,而且业务类都包含了CRUD的操作,那么我们可以使用一些代码生成工具来加速我们的开发,而且有些好的代码生成工具还包含了一些数据库的逻辑验证代码来确保我们把正确的数据保存到数据库中。

  下面我们就用一个例子来看看这种模式是如何应用的。例子还是采用之前谈到的Blog系统。

  注:在系列文章中,我将会采用各种不同的技术来实现系统,在下面的这个例子,我将会采用NHibernate为例子。大家理解代码就行了,然后按照自己的理解选用其他的技术。

  首先我们将会创建一个名为:ASPPatterns.Chap4.ActiveRecord的新的解决方案,然后添加一些项目,并且添加一些必要的dll引用,如下:

  然后我们在ASPPatterns.Chap4.ActiveRecord.UI.MVC中添加一个数据库:Blog.mdf,然后添加两张表:

  Posts表:

  Comments表:

  下面我们就来看看ASPPatterns.Chap4.ActiveRecord.Model中的Comment类:

  
  
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.ActiveRecord;

namespace ASPPatterns.Chap4.ActiveRecord.Model
{
[ActiveRecord(
" Comments " )]
public class Comment : ActiveRecordBase < Comment >
{
[PrimaryKey]
public int Id { get ; set ; }

[BelongsTo(
" PostID " )]
public Post Post { get ; set ; }

[Property]
public string Text { get ; set ; }

[Property]
public string Author { get ; set ; }

[Property]
public DateTime DateAdded { get ; set ; }
}
}


  代码中,可以看出Comment类和数据表Comments是对应的,而且在Comment加上了一些Attribute也表明这个属性和数据表中的列式对应的。我们的例子中采用了Castle Active Record框架,这个框架将会根据这些Attribute来自动生成一些需要的SQL。和我们用Linq To Sql 的原理一样。

  下面的Post类也是一样的:

  
  
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Queries;

namespace ASPPatterns.Chap4.ActiveRecord.Model
{
[ActiveRecord(
" Posts " )]
public class Post : ActiveRecordBase < Post >
{
[PrimaryKey]
public int Id { get ; set ; }

[Property]
public string Subject { get ; set ; }

[Property]
public string Text { get ; set ; }

public string ShortText
{
get {
if (Text.Length > 20 )
return Text.Substring( 0 , 20 ) + " ... " ;
else
return Text;
}
}

[HasMany]
public IList < Comment > Comments { get ; set ; }

[Property]
public DateTime DateAdded { get ; set ; }

public static Post FindLastestPost()
{
SimpleQuery
< Post > q = new SimpleQuery < Post > ( @" from Post p order by p.DateAdded desc " );

return (Post)q.Execute()[ 0 ];
}
}
}


  因为这个Blog系统比较的简单,而且逻辑不多,如果需要,大家可以再Model中加入更多的逻辑。下面我们就显示这些文章和评论,在显示层我们采用的ASP.NET MVC框架。我们创建一个BlogController来负责处理有关操作:

  
  
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using ASPPatterns.Chap4.ActiveRecord.Model;

namespace ASPPatterns.Chap4.ActiveRecord.UI.MVC.Controllers
{
public class BlogController : Controller
{
// GET: /Blog/
public ActionResult Index()
{
Post[] posts
= Post.FindAll();

if (posts.Count() > 0 )
{
ViewData[
" AllPosts " ] = posts;
ViewData[
" LatestPost " ] = Post.FindLastestPost();
return View();
}
else
{
return Create();
}
}

// POST: /Blog/
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateComment( string Id, FormCollection collection)
{
int postId = 0 ;
int .TryParse(Id, out postId);
Post post
= Post.Find(postId);

Comment comment
= new Comment();
comment.Post
= post;
comment.Author
= Request.Form[ " Author " ];
comment.DateAdded
= DateTime.Now;
comment.Text
= Request.Form[ " Comment " ];

comment.Save();

return Detail(post.Id.ToString());
}

// GET: /Blog/Detail/1
public ActionResult Detail( string Id)
{
ViewData[
" AllPosts " ] = Post.FindAll();

int postId = 0 ;
int .TryParse(Id, out postId);

ViewData[
" LatestPost " ] = Post.Find(postId);

return View( " Index " );
}

// GET: /Blog/Create
public ActionResult Create()
{
return View( " AddPost " );
}

// POST: /Blog/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
Post post
= new Post();
post.DateAdded
= DateTime.Now;
post.Subject
= Request.Form[ " Subject " ];
post.Text
= Request.Form[ " Content " ]; ;
post.Save();

return Detail(post.Id.ToString());
}
}
}

  例子很简单,大家看看就明白了。 然后添加对应的View:

  一个是显示文章要用的:

  一个是添加文章用的:

  页面的Source代码我就不列出来,大家可以下载代码自己看看,也是比较的简单。 然后我们需要到Global.asax文件中去加一些代码:

  Route配置:

  
  
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute(
" {resource}.axd/{*pathInfo} " );
routes.MapRoute(
" Default " , // Route name
" {controller}/{action}/{id} " , // URL with parameters
new { controller = " Blog " , action = " Index " , id = "" } // Parameter defaults
);
}


  启用Castle 的一些代码。

  
  
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);

IConfigurationSource source
= ConfigurationManager.GetSection( " activeRecord " ) as IConfigurationSource;
Castle.ActiveRecord.ActiveRecordStarter.Initialize(source,
typeof (Post), typeof (Comment));
}

  最后在web.config 中加上NHibernate的一些配置就行了,这里不列出来,大家看代码!(见谅)。

  从上面的一些工作量可以看出,用相应的Frameword来实现blog系统还是比较的快的。而且上面的例子中,业务类和表的结构很一致,这也是Active Record的特点和优势。但是如果业务类和数据表的结构不一致,而且逻辑也变复杂了,也就是出现了“抗阻不匹配”。如果还在这中模式上面坚持,会使后面的开始过程和代码维护变得困难,那么我们就得采用Domain Model模式来组织业务逻辑。

  上面的例子讲的很粗糙,因为上面的两种模式本身还是比较容易理解的,到了Domain Model模式的讲解的时候,会更加的详细。

  今天就到这里了,还是希望多多见谅,支持!谢谢啊!代码下载 

目录
相关文章
|
9天前
|
机器学习/深度学习 算法 文件存储
RT-DETR改进策略【模型轻量化】| MoblieNetV3:基于搜索技术和新颖架构设计的轻量型网络模型
RT-DETR改进策略【模型轻量化】| MoblieNetV3:基于搜索技术和新颖架构设计的轻量型网络模型
20 4
RT-DETR改进策略【模型轻量化】| MoblieNetV3:基于搜索技术和新颖架构设计的轻量型网络模型
|
13天前
|
机器学习/深度学习 算法 文件存储
YOLOv11改进策略【模型轻量化】| MoblieNetV3:基于搜索技术和新颖架构设计的轻量型网络模型
YOLOv11改进策略【模型轻量化】| MoblieNetV3:基于搜索技术和新颖架构设计的轻量型网络模型
47 10
YOLOv11改进策略【模型轻量化】| MoblieNetV3:基于搜索技术和新颖架构设计的轻量型网络模型
|
16天前
|
机器学习/深度学习 缓存 自然语言处理
DeepSeek背后的技术基石:DeepSeekMoE基于专家混合系统的大规模语言模型架构
DeepSeekMoE是一种创新的大规模语言模型架构,融合了专家混合系统(MoE)、多头潜在注意力机制(MLA)和RMSNorm归一化。通过专家共享、动态路由和潜在变量缓存技术,DeepSeekMoE在保持性能的同时,将计算开销降低了40%,显著提升了训练和推理效率。该模型在语言建模、机器翻译和长文本处理等任务中表现出色,具备广泛的应用前景,特别是在计算资源受限的场景下。
339 29
DeepSeek背后的技术基石:DeepSeekMoE基于专家混合系统的大规模语言模型架构
|
20天前
|
机器学习/深度学习 安全 算法
十大主流联邦学习框架:技术特性、架构分析与对比研究
联邦学习(FL)是保障数据隐私的分布式模型训练关键技术。业界开发了多种开源和商业框架,如TensorFlow Federated、PySyft、NVFlare、FATE、Flower等,支持模型训练、数据安全、通信协议等功能。这些框架在灵活性、易用性、安全性和扩展性方面各有特色,适用于不同应用场景。选择合适的框架需综合考虑开源与商业、数据分区支持、安全性、易用性和技术生态集成等因素。联邦学习已在医疗、金融等领域广泛应用,选择适配具体需求的框架对实现最优模型性能至关重要。
285 79
十大主流联邦学习框架:技术特性、架构分析与对比研究
|
Web App开发 SQL 前端开发
一起谈.NET技术,鲜为人知的ASP.NET MVC 2.0框架高效之谜
  要想建立开发环境,你需要安装Visual Studio 2008/2010 Beta 2,以及SQL Express 2005(可免费从MSDN下载)和MVC 2.0框架。我把本文中的示例Web应用命名为“Employee Master Information”。
1028 0
|
存储 缓存 .NET
一起谈.NET技术,提高ASP.NET应用程序性能的十大方法
  一、返回多个数据集   检查你的访问数据库的代码,看是否存在着要返回多次的请求。每次往返降低了你的应用程序的每秒能够响应请求的次数。通过在单个数据库请求中返回多个结果集,可以减少与数据库通信的时间,使你的系统具有扩展性,也可以减少数据库服务器响应请求的工作量。
1240 0
|
XML 前端开发 .NET
一起谈.NET技术,ASP.NET MVC 2生成动态表单的一种最简单的思路
  在BPM、OA等系统中,都会存在一个表单设计器。有些是通过操作gridview来完成一个表单的设计;有些是通过类似VS拖拽的方法完成一个表单的设计。很明显后面一种优越于前面一种。无论是哪种,最后都会产生一些XML之类的表单结构的数据。
1323 0
|
Web App开发 .NET 数据安全/隐私保护
一起谈.NET技术,ASP.NET身份验证机制membership入门——项目
  前面说了很多关于membership的内容,感觉内容有点凌乱,内容都是一个个知识点,下面我们通过一个小的项目,来把所有的相关内容串一下。   首先描述一下需求:   我们要做一个最简单的网站。有三类用户:匿名用户,员工,管理员,网站结构如下:        admin目录下的页面只允许admin角色的用户访问,employee目录下的页面只允许emp角色的用户访问。
1116 0
|
缓存 算法 .NET
一起谈.NET技术,ASP.NET缓存全解析7:第三方分布式缓存解决方案 Memcached和Cacheman
  ASP.NET缓存全解析文章索引 ASP.NET缓存全解析1:缓存的概述 ASP.NET缓存全解析2:页面输出缓存 ASP.NET缓存全解析3:页面局部缓存 ASP.NET缓存全解析4:应用程序数据缓存 ASP.NET 缓存全解析5:文件缓存依赖 ASP.NET 缓存全解析6:数据库缓存依赖 ASP.NET 缓存全解析7:第三方分布式缓存解决方案 Memcached和Cacheman   Memcached — 分布式缓存系统    1.Memcached是什么?   Memcached是高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。
1204 0
|
前端开发 .NET
一起谈.NET技术,ASP.NET MVC 2扩展点之Model Binder
  Model Binder在Asp.net MVC中非常简单。简单的说就是你控制器中的Action方法需要参数数据;而这些参数数据包含在HTTP请求中,包括表单上的Value和URL中的参数等。而ModelBinder的功能就是将这些个表单上的Value和URL中的参数换成对象,然后将这些对象绑定到Action的参数上面。
1082 0