软件架构设计 2. 领域层的设计模式

        今天,这篇文章我们主要会讲的是在企业应用软件架构中,领域层也就是业务逻辑层的设计模式。主要分为三个部分来讲解,第一个部分讲面向过程与面向对象的程序设计方式的区别;第二个部分讲怎么看类图与时序图,我认为这两种图在软件工程中是最适合用来描述面向对象的程序结构与流程的,任何软件,只要有了这两种图,那么,大概的程序结构就出来了。以前我在国企的时候老是要求软件外包商提供类图和时序图,但是遗憾...
摘要由CSDN通过智能技术生成

        今天,这篇文章我们主要会讲的是在企业应用软件架构中,领域层也就是业务逻辑层的设计模式。主要分为三个部分来讲解,第一个部分讲面向过程与面向对象的程序设计方式的区别;第二个部分讲怎么看类图与时序图,我认为这两种图在软件工程中是最适合用来描述面向对象的程序结构与流程的,任何软件,只要有了这两种图,那么,大概的程序结构就出来了。以前我在国企的时候老是要求软件外包商提供类图和时序图,但是遗憾的是,我发现在中国,估计除了外企,小的民营软件公司能够画出类图和时序图的公司是凤毛麟角吧,至少我现在还没看到过一家民营软件公司能够工工整整的交出软件的时序图和类图,我没进过BAT以及华为这样的大的民营公司,因此不知道大的民营公司在这一块做得怎么样。但是类图、时序图对于软件外包的工程来说,尤其的重要。原因是第一:如果外包公司撤出,那么本公司的工程师需要维护软件的时候,如何了解整个软件的细节?第二:就算外包公司永远不撤出,那么如果外包公司内部的人员离职,要如何保证外包公司内部的新进员工可以接手对这个软件进行修改和维护?第三部分写领域层的设计模式。

       因为三个部分的内容太多了,因此第一部分与第二部分的内容以文章链接的方式给出来。

       好了,下面开始讲第一部分:什么是面向过程和面向对象的程序设计方式?具体请看这里:面向过程与面向对象:两种程序设计方式的对比

       第二部分:什么是类图和时序图?具体请看这里:描述程序结构的利器:类图 与时序图

       因为在第三部分需要用到面向过程,面向对象的概念,需要使用时序图和类图类看程序结构,因此在讲正题之前先写了这么多基础知识进行铺垫。

第三部分:领域层的设计模式

      领域层的设计模式主要有三种:事务脚本模式、领域模型模式和表模块模式。在这个部分中,会先讲解每一种设计模式的定义、适用场景和优缺点,最后再通过分别使用这三种设计模式针对同一个需求场景进行程序设计,这样就能具体看出这三种设计模式到底有什么不同。

      1. 事务脚本模式   

      (1)什么是事务脚本?

        事务脚本是使用过程来组织业务逻辑,每个过程处理来自表现层的单个请求,在过程中直接调用数据库 ,或者只通过一个简单的数据库封装类来访问数据库。通俗的来说,事务脚本就是让每个过程对应用户可能做的一个动作。

       组织数个事务脚本的方式有两种:第一种,将数个事务脚本放在一个类中,每个类围绕一个主题将相关的事务脚本组织在一起;另一个方法则是每一个事务脚本对应一个类,此时需要使用命令模式。定义一个所有命令的父类,在父类中声明事务脚本逻辑适合的执行方法。

       (2)事务脚本模式的适用场景

        对于只有少量逻辑的应用程序来说,使用这一模式非常的简单和自然,无论在性能上还是理解上都不会带来太大的开销。

另外,如果使用事务脚本来实现软件架构,一个事务脚本对应一个客户的请求,当发出请求的对象和执行请求的对象不一样的时候,或者需要解耦的时候 ,使用命令模式非常适合。什么是命令模式,后面会专门写一篇文章来解释。

       (3)事务脚本设计模式的优缺点

        优点:简单、设定事务便捷的方法显而易见,一个事务开始于其脚本的打开,终于其脚本的关闭。

        缺点:逻辑复杂时,若干事务需要做相似的动作时,多个脚本中包含相同代码,造成代码余。

       2.领域模型模式

      (1)什么是领域模型?

       领域模型是一个完整的由对象组成的层。数据和业务处理一般整合在一起。简单领域模型看起来与数据库设计很类似,这种设计中几乎每一个数据库表都与一个领域对象对应。而复杂的领域模型则与数据库设计不同,它使用继承、策略和其他设计模式,是一张由互联的细粒度对象组成的复杂网络。

        (2)领域模型的适用场景

       当软件系统的业务非常复杂的时候,比较适合使用领域模型模式。领域模式使用面向对象的设计方式,使得代码的耦合度比较低,便于后期对于软件功能进行扩展和维护。

        (3)领域模型的优缺点

         优点:代码具有高内聚、低耦合的特点,后期对于软件的扩展、修改和维护的成本低。

         缺点:设计比较复杂,对于程序员的能力要求比较高,并且,在软件功能增加的过程当中,如果出现冗余代码,需要对代码进行重构。

         3.表模块设计模式

        (1)什么是表模块模式?

         表模块是处理某一个数据库表或视图中所有行的业务逻辑的一个实例。表模块以一个类对应数据库中的一个表来组织领域逻辑,而且使用单一的类实例来包含将对数据进行的各种操作程序。它与领域模型模式的主要区别在于,如果你有许多订单,领域模型对每一个订单都有一个对象,而表模块则只用一个对象来处理所有的订单。

表模块中的“表”暗示着数据库中的每一个表对应一个表模块,虽然大多数情况下都是如此,但也并非绝对。

        (2)表模块模式的适用场景

        当使用记录集存取表数据时应当使用这一模式。记录集是使用SQL语句查询数据库表得到的一个数据集合。另外,当使用 .Net技术来进行开发时,很适合用表模块模式,因为.Net中有非常多的API直接支持数据库以及数据集的操作。

       (3)表模块模式的优缺点

        优点:与软件架构中已有的部分衔接非常方便。表模块工作在记录集上,可以将处理后的结果直接传给GUI(用户界面)显示。

        缺点:表模块并没有给你提供完全的面相对象能力来组织复杂的领域逻辑。你不能在实例之间直接建立关联,而且多态机制也无法工作良好。因此,当处理复杂逻辑时,领域模型将是一个更好的选择。

       领域层的三种设计模式的概念都讲完了,总的来说,事务脚本模式适合处理简单的逻辑,系统很小不复杂时可采用这种模式;业务逻辑复杂采用领域模式;如果需要在记录集上工作,可采用表模块模式,当然这三种方式也可混用,主要还是根据系统的功能复杂度与需求来定。

        下面,我们将从一个具体的需求入手,使用类图和时序图来看看三种设计模式在设计软件时到底有什么不同。这个需求例子以及实现来自于《企业应用架构模式》这本书。

        需求:假定某公司出售三种产品:文字处理软件、数据库和电子表格软件。根据规则,当签下一个售出文字处理软件的合同时,所有收入可以立即入账。如果售出的是一个电子表格软件,则当天入账三分之一,60天后再入帐三分之一,剩下的三分之一90天后入帐。如果售出的是数据库,则当天入账三分之一,30天后再入帐三分之一,剩下的三分之一60天时入帐。设计一个程序用来实现两个功能:(1)确定一个合同应该收多少钱,这些钱需要如何收  (2)可以查询到在某个日期前,一个合同应该收到多少笔款项

       数据库中有三个表,分别是对应产品、合同以及合同中每一个收入款项的表,表结构如下:

       CREATE TABLE products(ID int primary key, name varchar, type varchar)

       CREATE TABLE contracts(ID int primary key, product int, revenue decimal, dateSigned date)

      CREATE TABLE revenueRecognitions(contract int, amount decimal, recognizedOn date,

                                    PRIMARY KEY(contract, recognizedOn))

        products表中是所有产品信息,包括每个产品的名称以及在表中的编号。Contracts表中记录的是签订的每一个合同,每条数据对应签订的一个产品的合同,以及合同金额。revenueRecognitions表中对应的是每个合同应收的每一笔款项,例如:电子表格软件的合同应该有三笔应收款项在这个表中,而如果是文字处理软件的合同,则只有一笔应收款项在这个表中。

       1.使用事务脚本模式实现以上需求

        在事务脚本模式中,可以设计成一个类对应一个事务,也可以将相关的多个事务组织在 一个类中,鉴于这个需求很简单,只有两个事务,因此就只设计了一个类RecognitionService,它包含两个函数对应需要处理的事务,请参看下面的类图 图1:RecognitionService类中的calculateRevenueRecognitions 函数实现需求(1)确定一个合同应该收多少钱,这些钱需要如何收;recognizedRevenue函数实现需求(2)可以查询到在某个日期前,一个合同应该收到多少笔款项。另外,为了将数据和业务逻辑区分开,设计了DataGateway这个类专门与数据库打交道。

 

             

                                                                                       图     1

          下面,我们用一张时序图(图2)来看看需求(1)是如何实现的?

 

               

                                                                                        图      2

       在类RecognitionService的calculateRevenueRecognitions函数中调用了类DataGateWay中的findContract方法,这个方法查询数据库返回了包含contract记录的结果集contract resultset给calculateRevenueRecognitions 函数。从contract resultset中可得到product type,然后就可根据不同产品种类的收款规定来确定这个合同中的这种产品应该如何收款了,每一笔应收款项,都由DataGateway类插入到数据库中。

       需求(2)的实现就更加简单了,直接在RecognitionService的recognizedRevenue函数中调用DataGateway的findRecognitionsFor函数,将返回的结果集中的每一项数据的金额加起来就行了。

         实现需求(1)与需求(2)的示例代码如下:

         class DataGateway{

        public ResultSet findRecognitionsFor(long contractID, MfDate asoff) {

                //执行查询语句:

                //SELECT amount FROM revenueRecognitions WHERE contract = contractID AND

                 recognizedOn <= asoff

        }

       

        public ResultSet findContract(long contractID) {

                //执行查询语句:

                //SELECT * FROM contracts WHERE id = contractID

        }

       

        public void insertRecognitions(long contractID, Money amount, MfDate asof) {

                //执行插入语句:

                //INSERT INTO revenueRecognitions(contractID, amount, asof)

        }     

}

 

class RecognitionsService {

        private DataGateway db;

        public Money recognizedRevenue(long contractNumber, MfDate

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值