走向.NET架构设计—第三章—分层设计,初涉架构

简介:
走向.NET 架构设计分层设计,初涉架构(前篇)
  前言:本篇不打算接着上一篇来,这没有关系,以为内他们之间的联系不大,以后我再补上。因为之前一直在谈论设计,也谈了一些TDD 的东西,大家反应觉得讲述的还是有点,所以打算换一种方式:先讲述一些例子,把一些思想穿插着讲述,理论的东西最后最为总结。希望大家支持!
 
本篇主要讲述 ASP.NET 应用中如何进行逻辑分层。本篇的前篇会从 Smart UI  反模式和它的一些缺点开始讲述,然后一步步的讲述如何逻辑分层,而且在后篇中也会给出一个 ASP.NET 设计中常用的仅供参考的分层架构的 Demo
 
 
一个稳定和易维护的系统必须建立在一个好的基础之上。计划和设计一个好的架构对一个项目的成败起着至关重要的作用。可能在我们一般做项目的时候,经验告诉我们:3层,N层的设计,基本就能把问题解决了,很多的情况确实是这样的。在提出一个设计的时候,常常要考虑为什么要这样划分结构,而且常常要承担风险和责任,特别是万一这个项目因为最初的设计而导致崩溃,那就郁闷了。所以设计的提出一定和考虑业务。
 
  下面就先来看看Smart UI的设计方式。
  Smart UI
想想我们最初是如何开发ASP.NET的应用的:在页面设计界面中把界面布局好,然后双击控件就开始编写功能代码。很多的时候把逻辑判断和数据访问都写在页面的.cs的文件中。后来我们学习到了分层,逐渐的明白了这种方式的缺点:导致业务逻辑代码到处分散而且重复,不利于以后的更改和维护等。
 
尽管有上述说的一些缺点,Smart UI还是有它的用途的,如为项目快速的建立一个原型或者开发一个功能比较的小的项目。还有一个问题,如何最初用Smart UI的方式开发的小项目很成功,慢慢的变大,变复杂了,那么很多的问题就出来了。就像Flower在架构模式一书中提到的:尽量用领域模型来组织一个项目的业务逻辑,尽管在开始的时候逻辑不复杂或者看不出这种方式的好处,一旦项目变化,好处就显而易见了。在对项目原型开发中,尽量不用Smart UI
 
其实Smart UI最大的问题就是:职责不清把所有的东西全部写在一起。
为了和以后讲述的内容的比较,我还是写一个例子出来,很多朋友都已经对这种Smart UI的开发方式很熟悉了,可以跳过下面的例子。 
 
这里以产品管理系统中的一个简单场景为例:显示所有的产品信息。例子采用ASP.NET来实现,步骤如下:
     1.创建AgileSharp.Chapter3.AntipatternASP.NET项目,如图 所示:
 
     2.  选择App_Data文件夹,添加数据库OrderManagement.mdf,如图 所示 
 
 
 
 
3. 在新加的数据库文件上右击,并且打开。然后添加一个新表:如下:
 
 
其中ProductId设置为自动标示。
然后保存为Products表。
 
4. 添加一些测试的数据. 
     5. 然后选择Products表,并且把表拖放到Default.aspx页面上。这样之后,在页面上就自动添加一个GridViewSqlDataSource.
 
界面就如下图:
 
6. 我我们添加额外的两列来显示折扣信息和库存信息。
 
7. 然后,我们在Default.aspx.cs后编码:
 
protected void gvProduct_RowDataBound(object sender,GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
        {
        intproductId = int.Parse(((System.Data.DataRowView)e.Row.DataItem)
        [“ProductId”].ToString());

        decimal price = decimal.Parse(((System.Data.DataRowView)e.Row.DataItem)
            [“Price”].ToString());

            Label lblDiscount = (Label)e.Row.FindControl(“lblDiscount”);

        lblDiscount.Text = DisplayDiscount
    (ApplyDiscountsStrategy(productId, price));

       }
}
        
在上面的 GridView1_RowDataBound方法在GridView的每个row被创建的时候调用。这个方法获取每个产品的推荐的零售价格RRP(Recommend Retail Price),然后调用 DisplayDiscountDisplaySavings方法来获取折扣和库存,然后再更新UI的显示。
         在上面的代码中,就将计算折扣和计算库存的逻辑写在了UI中,而且数据的访问代码也写在UI中了。这就意味着:如果我们想要在不同的页面显示产品的信息,那么这些逻辑就得一遍遍的重写。如果我们在加一些新的功能,那么页面后面的代码就开始修改,开始缝缝补补。
 
  解决Smart UI的方法就是划分职责,我想大家都知道“单一职责的原则”,这个原则不仅仅适用于类,方法,而且对项目的层次划分也有作用。分层,最主要的目的就是:把不通的功能放在各自对应的地方,这样清晰的职责划分,也是对变化点进行分离。
  下面的图就是一个典型的企业级ASP.NET项目的分层结构:
 
  下面我们就来看看,按照我们的一般的分层的经验来如何设计这功能:
     下面,我们再次来练下手,重新设计前面提到的订单管理系统,使其功能适应新的需求(很多时候,重新设计基本不可能的,所以在开始设计时就需要考虑清楚,这里重新设计只是从举例的角度来考虑的):
(1) 支持用户通过网页或PC桌面程序来访问系统。
(2) 订单管理系统需要为其他的系统(如财务系统等)提供服务。
(3) 订单的一些处理流程和相关的业务处理在其他的系统要用到。
(4) 还有更多的需求,等待确认。
 
  注:朋友们一眼就应该可以看出,这些类库的命名是反映了一些DDD的一些概念,但是,不是说在一个项目的开发中用了这些概念名词就表明就开发的方式是DDD了。
 
  这里我先提一下上面类库的一起名字:尽管有关DDD和一些架构模式的概念我在以后的文章中会讲,但我这里还是先给大家提一下,目的仅仅是让大家对这个例子有一些更好的了解。
  在DDD中,一直主张业务模型,也就是我们常常所说的业务类,例如之前例子中的Product,只关注自身的业务逻辑,而不管如何去获取和保存数据,这些对数据的操作完全交给另外的对象去执行,也就是Repository,这样就达到了DDD中所说的PIPersistence Ignore)。所以在上面的例子中,ASPPatterns.Chap3.Layered.Model就代表了一个业务模型,它之所以被Repository引用,是因为Repository负责将Model的数据持久化到存储设备中,而Model不管这些事情了。
 
  在讲之前,首先给大家统一 一下Service的概念。 
  有时在类的设计过程中,有些行为不适合放在任何的一个类中,如果把这些行为放在一个不真正拥有它的类中,只能把类的职责搞混了。为了给这些行为一个安置的地方,我们常常把这些行为放在一个称为服务的类中。
 
  作为服务的类一般没有状态的,可以简单的作为一个提供操作接口实现。
  在DDD中,Service也是用来提供一种服务的。很多人看到了DDD的类层次结构是这样的:Repository---Model---Service--- Presentation(包括本例),所以都以为Service只能出现在Model的上一层,如果看到Repository-- Service ---Model---Service--- Presentation这样的层次结构,又作何感想。如果被这些所谓的结构搞迷惑了,那就说明对DDD的理解只是在于“形”上。Service就是向外部提供的功能接口,和我们常见的Web Service的概念很相似,例如的Web Service就是向外部系统提供一些功能的。
  我们来看下面的一个图:
 
 
 
  有时候之所以要在Model层之上加上一个Service层,主要的原因就是实现粗颗粒度的API,往往和系统的User Case有一定的联系。例如,如果在系统用例中要实现一个用户订单的处理,那么可能就涉及到Customer, Product,Order等类,当然,如果我们调用这些类来共同完成这个任务是没问题的,但是这样就向调用者暴露这些类之间的复杂的关系,而且如果处理的过程变化了,那么调用者的代码就要改变,如果把这个处理的方法放在上面的任意一个类中,又显得不伦不类,这里的Service功能就类似于设计模式中的Façade外观模式。这样就向外界提供简单的API,向外界提供订单处理的服务!
 
  所以在一般在DDD中业务层被划分为两个逻辑层:Model (提供细粒度的业务逻辑处理,也便于重用), Service(提供业务处理的流程,提供粗颗粒度的供外部调用的方法)。
 
  但是,我们常见到的Model层之上的Service层仅仅只是对CRUD的再次封装,一个可能的原因就是业务不是很复杂,这时其实这个Service层可以拿掉的,但是考虑到以后可能逻辑会更多更复杂,所以还是保留Service这层。
 
  其实在Repository上的那个Service也是同样的概念。例如发送邮件通知用户的功能。例如上图中的最上层的Service可以调用业务层和基础设施层的Service来共同完成一个事情。
 
  今天的上篇的就讲述到这里吧,下篇会用一个例子,代码量还是有点的!敬请关注!
  大家感兴趣,我们下篇讲述!























本文转自yanyangtian51CTO博客,原文链接:
http://blog.51cto.com/yanyangtian/410222
 ,如需转载请自行联系原作者


相关文章
|
11天前
|
设计模式 存储 前端开发
揭秘.NET架构设计模式:如何构建坚不可摧的系统?掌握这些,让你的项目无懈可击!
【8月更文挑战第28天】在软件开发中,设计模式是解决常见问题的经典方案,助力构建可维护、可扩展的系统。本文探讨了.NET中三种关键架构设计模式:MVC、依赖注入与仓储模式,并提供了示例代码。MVC通过模型、视图和控制器分离关注点;依赖注入则通过外部管理组件依赖提升复用性和可测性;仓储模式则统一数据访问接口,分离数据逻辑与业务逻辑。掌握这些模式有助于开发者优化系统架构,提升软件质量。
27 5
|
11天前
|
XML 开发框架 .NET
.NET框架:软件开发领域的瑞士军刀,如何让初学者变身代码艺术家——从基础架构到独特优势,一篇不可错过的深度解读。
【8月更文挑战第28天】.NET框架是由微软推出的统一开发平台,支持多种编程语言,简化应用程序的开发与部署。其核心组件包括公共语言运行库(CLR)和类库(FCL)。CLR负责内存管理、线程管理和异常处理等任务,确保代码稳定运行;FCL则提供了丰富的类和接口,涵盖网络、数据访问、安全性等多个领域,提高开发效率。此外,.NET框架还支持跨语言互操作,允许开发者使用C#、VB.NET等语言编写代码并无缝集成。这一框架凭借其强大的功能和广泛的社区支持,已成为软件开发领域的重要工具,适合初学者深入学习以奠定职业生涯基础。
68 1
|
13天前
|
监控 安全 中间件
Python Django 后端架构开发: 中间件架构设计
Python Django 后端架构开发: 中间件架构设计
19 1
|
26天前
|
存储 消息中间件 JSON
|
13天前
|
存储 缓存 Cloud Native
MPP架构数据仓库使用问题之ADB PG相比Greenplum的HAWQ在架构设计上有什么不同
MPP架构数据仓库使用问题之ADB PG相比Greenplum的HAWQ在架构设计上有什么不同
|
2月前
|
运维 Java Docker
业务系统架构实践问题之在某些情况下,将能力代码和业务逻辑严格分层可能是一个挑战问题如何解决
业务系统架构实践问题之在某些情况下,将能力代码和业务逻辑严格分层可能是一个挑战问题如何解决
|
2月前
|
存储 搜索推荐 API
业务系统架构实践问题之分层架构中的四层定位是什么
业务系统架构实践问题之分层架构中的四层定位是什么
|
2月前
|
缓存 项目管理
项目管理定义问题之DDD架构的分层架构中基础层作用是什么
项目管理定义问题之DDD架构的分层架构中基础层作用是什么
|
2月前
|
存储 消息中间件 Kafka
细说数据仓库分层架构
【7月更文挑战第20天】数据仓库分层架构包括缓冲层、操作数据层、明细数据层、汇总数据层和数据集市层。
|
10天前
|
Kubernetes Cloud Native Docker
云原生之旅:从容器到微服务的架构演变
【8月更文挑战第29天】在数字化时代的浪潮下,云原生技术以其灵活性、可扩展性和弹性管理成为企业数字化转型的关键。本文将通过浅显易懂的语言和生动的比喻,带领读者了解云原生的基本概念,探索容器化技术的奥秘,并深入微服务架构的世界。我们将一起见证代码如何转化为现实中的服务,实现快速迭代和高效部署。无论你是初学者还是有经验的开发者,这篇文章都会为你打开一扇通往云原生世界的大门。
下一篇
DDNS