`

项目总结-耦合Couple

阅读更多

 

耦合Couple

 

 

 引言

  本文将到的耦合是指的软件开发中的耦合,而且是代码方面的耦合。包括后面讲到的分层,也只是逻辑分层,不是物理分层。

  耦合是我们做软件开发经常会遇到的词汇,尤其是在使用面向对象语言进行开发的时候。看到的相关资料也都在说要低耦合,减少耦合。

  尽管我们加入了设计模式,分了层,分了模块,做了等等的工作,还是发现存在耦合,还是有人说耦合高了,导致不能修改,修改、维护的代价太大了。直接导致工期不能固定,不能预估,不知道什么时候才能完成任务。

  下面就让我们分析一下耦合从何而来?耦合又是什么呢?如何降低耦合呢?耦合能否不再存在呢?耦合可以解除吗?where is the couple?what is the couple?

 

 

 

正文
   在我看来,尽管我们分层了,分了模块,应用了设计模式,耦合永远还是存在的。我们能做的是给耦合定义一个限度,做到什么程度就可以了呢?这需要根据项目的context来决定。context包括:时间,资金,人员,需求等一下客观因素。

  就像我们分的层一样,分层式为了降低耦合,但是分了层,层之间的耦合是降低了,可是在层的内部的耦合还是需要重新定义的,这里面的耦合不比层之间的耦合要低。通常我们的项目会分为三层:数据访问层、业务逻辑层、表现层,如果需要的话,我们还会加入服务层。还有在这些层之间交互的数据,实体。因此,我觉得耦合包括:实体耦合、数据访问层耦合、业务层耦合、服务耦合(如果存在服务层)。

  1、实体耦合

  什么叫做实体耦合呢?就是实体的公用,尤其存在于从数据库直接生成的实体。例如一个申请实体,需要申请人填写一些信息,例如:姓名、申请标题、内容。然后由审批的人查看,进行审批,会加入意见,是否同意等信息。同时,申请的时间和处理申请的时间也是关键的信息,也需要在数据库中记录。

 

  生成下面的实体

 

 

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BeautyCode.TDD.ConApp
{
   
public class Application
    {
       
public Guid ApplcaitonID
       {
           
get;
           
set;
       }
       
public Guid ApplyerID
       {
           
get;
           
set;

       }
       
public string ApplyTitle
       {
           
get;
           
set;
       }
       
public string ApplyContent
       {
           
get;
           
set;
       }
       
public DateTime ApplyDate
       {
           
get;
           
set;
       }
       
public Guid Checker
       {
           
get;
           
set;
       }
       
public DateTime CheckDate
       {
           
get;
           
set;
       }
       
public CheckResult CheckResult
       {
           
get;
           
set;
       }
       
public string CheckReason
       {
           
get;
           
set;
       }
    }
    [Flags]
    
public enum CheckResult
    {
        Waiting
=1,
        Agree
=2,
        Disagree
=4
    }
}
  

 

  其实在添加申请的时候,数据库applicaiton表中的有些字段是不用添加的,例如:处理时间,处理人之类和处理相关的字段。那么这个实体会让做添加功能的程序员很是疑惑,那些字段是必须要赋值的呢?那些不用去管呢?这个类会造成疑惑。就算他通过了解知道了他需要赋值的字段。在后面肯定有一个申请人和审批人查询申请信息的功能。

  有一天需求有了变化,申请人多了一个选项,需要他选择,当然了,内容会加入数据库。因为审批人建立了一些申请的类型,可以对申请信息进行分类,方便统计。

  

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BeautyCode.TDD.ConApp
{
   
public class Application
    {
       
public Guid ApplcaitonID
       {
           
get;
           
set;
       }
       
public Guid ApplyerID
       {
           
get;
           
set;

       }
       
public string ApplyTitle
       {
           
get;
           
set;
       }
       
public string ApplyContent
       {
           
get;
           
set;
       }
       
public DateTime ApplyDate
       {
           
get;
           
set;
       }
       
public Guid Checker
       {
           
get;
           
set;
       }
       
public DateTime CheckDate
       {
           
get;
           
set;
       }
       
public CheckResult CheckResult
       {
           
get;
           
set;
       }
       
public string CheckReason
       {
           
get;
           
set;
       }
       
public ApplyType ApplyType
       {
           
get;
           
set;
       }
    }
    [Flags]
    
public enum CheckResult
    {
        Waiting
=1,
        Agree
=2,
        Disagree
=4
    }
  [Flags]
    
public enum ApplyType
    {
        Family=1,
        Social=2,
        Personal=4
    }
}

 

  数据库要添加一个字段,类要添加一个字段。由于实体是公用的,添加、查询、显示都是用一个实体,但是有的字段有的时候是不用的。这个就给后面的维护带来很大的困难,可能会发生错误,这个类背负了过多的责任。如果这个字段只是为了添加功能而设立的,显示和查询功能用这个实体的时候就不应该看见它,要不然他们就需要知道这个字段的意思,是否需要赋值。而且加一个字段,只是为添加功能而设计的字段,需要担心是否显示和查询功能会有问题。就像上面我们的枚举量是从1开始的,没有0。在显示的时候,如果没有对这个字段赋值,那么这个属性就是枚举量的默认值,0,然后就会报错,不存在0的枚举量值。

  这样的类应该被分为多个,添加就是一个添加用的实体,每一个字段都是要赋值的,这样就不会给做添加功能的程序员带来麻烦,减少沟通的成本,加快开发的速度。

  实体类应该是专用的,每个实体类都有一个场景,都有自己的context,不应该混用。如果混用,就是实体耦合。这个耦合也是我们应该在最初的时候需要注意的。

  2、数据访问层耦合

  什么叫做数据访问层耦合呢?先让我们看一个例子。

  查询,根据界面上的条件查询申请信息。我们的用户有两类,一个是申请者,一个是审批者。申请者应该查询自己的申请,审批者则可以查询所有的申请。于是有了下面的方法。根据申请时间、申请类型、标题进行查询。

  

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BeautyCode.TDD.ConApp
{
   
public     class ApplicationDataAccess
    {

       
public List<Application> Find(DateTime? applyDateBegin, DateTime? applyDateEnd, ApplyType applyType, string title)
       {
           List
<Application> applications = null;

           
return applications;
       }
    }
}
  

 

  可是有一天,上面说需要添加一个条件,就是处理结果,好吧,方法加一个参数吧。后来又说了,加上一个处理时间的参数吧,好吧,加上两个吧。等等,参数列表会越来越长,好像会没有尽头。我们来小小的改造一下,建立一个查询实体,需要查询的字段都放在里面。

  

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BeautyCode.TDD.ConApp
{
   
public     class ApplicationDataAccess
    {

       
public List<Application> Find(ApplicationFind find)
       {
           List
<Application> applications = null;

           
return applications;
       }
    }
   
public class ApplicationFind
   {
       
public DateTime? ApplyDateBegin
       {
           
get;
           
set;
       }
       
public DateTime? ApplyDateEnd
       {
           
get;
           
set;
       }
       
public ApplyType ApplyType
       {
           
get;
           
set;
       }
       
public string Title
       {
           
get;
           
set;
       }
       
public CheckResult CheckResult
       {
           
get;
           
set;
       }
   }
}

 

  这下好了,以后如果需要添加查询条件只需要打开find实体,添加一个属性就可以了。当然了,存储过程和一些代码还是需要修改的。可是毕竟参数不会越来越长了,几个参数看起来也比较舒服。因为在实际的项目中,一个方法,除了这个参数,肯定会有其他的参数,例如方法访问者的信息,用来验证用户合法性,还可能会包括一些异常信息的反馈等等。

  过来几天,问题又来了。申请者需要加一个条件,可是审批者还是原来的条件。好吧,在查询方法中,判断一下用户的类型,然后决定使用的存储过程。然后处理查询结果的时候,也需要进行判断。而且写好之后,除了测试申请者用户,还需要测试审批者用户,防止审批者使用这个方法出现问题。

  

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BeautyCode.TDD.ConApp
{
   
public     class ApplicationDataAccess
    {

       
public List<Application> Find(ApplicationFind find,UserType userType)
       {
           List
<Application> applications = null;

           
if (userType == UserType.Applyer)
           {
           }
           
else
           {
           }

           
return applications;
       }
    }

   
public enum UserType
   {
       Applyer,
       Checker
   }
   
public class ApplicationFind
   {
       
public DateTime? ApplyDateBegin
       {
           
get;
           
set;
       }
       
public DateTime? ApplyDateEnd
       {
           
get;
           
set;
       }
       
public ApplyType ApplyType
       {
           
get;
           
set;
       }
       
public string Title
       {
           
get;
           
set;
       }
       
public CheckResult CheckResult
       {
           
get;
           
set;
       }
   }
}
  

 

  这样每次申请者添加查询条件,都要修改这个方法,还要防止不要破坏审批者使用这个功能。

  如果以后加入几种用户类型呢?if。。。else。。。会越写越长,这个方法会越来越难以维护。维护之前要区分那一段是给那一种用户的,修改一种用户的查询,不要影响了别人。如果存储过程用的是一样,那就更是痛苦了,在存储过程中还需要一堆的if。。。else。。。,那个维护起来就更是麻烦了。很是痛苦。

  这就是数据访问层的耦合。这时候我们应该给每一种用户写一个查询方法,每个用户都有自己的find实体,对应一个自己的存储过程。做到方法和存储过程的专用。下回再来修改一种用户的查询功能的时候,就不用害怕会影响别人了,不用测试其他的用户类型了。

  3、业务逻辑层耦合

  什么是业务逻辑层耦合呢?

  其实和数据访问层耦合差不多,也是由于方法公用产生的。应该用同样的方法来解决,方法专用,不要大家混用一个。

  4、服务层耦合

  什么时候服务层耦合呢?

  也是基于方法的耦合?解决方法同上。

  5、面向对象和耦合

  封装、继承、多态是面向对象的三个特征。是不是使用面向对象就可以避免耦合呢?答案是:No。

  尤其在使用了其中的继承之后,不仅不是消除耦合,反而是引入了耦合。因为,一个对象继承另外一个对象,如果基类修改了,那么继承类也被迫需要进行修改,这不就是引入了耦合,甚至是加重了耦合吗?

  继承就代表加重耦合的程度,估计这也是为什么继承不被推荐使用的原因之一吧。

结论

  结论就是耦合永远无法消除,我们能做的就是尽量的减少耦合。而且面向对象也不能消除耦合,反而用的不好,还会加重耦合的程度。

   

 

1、实体的专用性

1)        尽量的保持实体的专用性,也就是一个功能的方法,虽然和两外一个方法的返回结果类似,可能只需要添加一两个属性,这样的情况,重新建立实体,方便后面可能对这两个方法返回内容的修改不至于相互影响。

2)        尽量保持一个实体中的每一个属性,每一个被赋值的属性,将来都会用到,否则减少实体的属性,或者新建一个实体,使用正好合适的属性个数。

 

3)        分离添加和显示用的实体,因为添加可能不是每个字段都需要赋值,或者一些值是默认值。

 

4)        分离不同类型的用户使用的实体,尽管是相同的功能。可以在类名添加ForPlanter之类的后缀来解决。因为不同用户关注的点不同,关注的属性肯定不相同。而且修改也不影响其他类型用户的使用。

 

2、方法的专用性

 

保持方法的专用性,分离不同用户的业务方法和数据访问方法。也是为了后面的修改,不至于影响其他用户功能的使用。

 

3、系统划分

先按照功能模块或者是服务的对象主体来划分系统,划分为子系统。然后再每个子系统中分层,子系统之间的交互使用接口。子系统相关的后台代码独立,方便日后维护升级。

 

分享到:
评论

相关推荐

    耦合电感的伏-耦合电感的串并联和去耦等效电路.ppt

    1. 耦合电感的伏-耦合电感的串并联耦合电感的伏-耦合电感的串并联是指耦合电感在电路中的串并联连接,包括耦合电感的同名端、耦合系数、电压电流关系等。 2. 耦合电感的去耦等效电路耦合电感的去耦等效电路是指耦合...

    \MTK平台板测校准综测仪8960-耦合测

    3. **丰富的测试项目**:包括但不限于GSM/GPRS/EGPRS(EDGE)、CDMA/1xEV-DO、WCDMA/HSDPA等,适用于手机研发、生产等多个环节。 4. **可靠的测试结果**:提供了稳定的基站仿真能力,确保了测试结果的准确性和可靠性。...

    flac-pfc耦合隧道.txt

    flac-pfc耦合隧道.txt

    西门子RS 485-IS耦合器.pdf

    西门子RS 485-IS耦合器是一款用于将PROFIBUS-DP信号转换为具有本质安全特性(本质安全型防爆类型i)的PROFIBUS RS 485-IS信号的设备。耦合器在其中充当安全屏障的作用,确保了在存在爆炸性气体或粉尘环境中设备的...

    模块独立思维导图-耦合、内聚的种类

    ### 模块独立思维导图-耦合、内聚的种类 #### 一、概述 在软件工程领域中,为了确保软件系统具有良好的可维护性和可扩展性,开发者需要重视模块设计的质量。其中,模块独立性是衡量软件设计好坏的重要标准之一。...

    半导体中的激子-声子耦合:基本理论.pdf

    半导体中的激子-声子耦合:基本理论 半导体材料是一种特殊的材料,它的物理性质受到激子-声子耦合的影响。在半导体材料中,激子是一种激发态,声子是一种晶格振动,它们之间的耦合是研究半导体物理性质的关键。激子...

    车辆-轨道耦合动力学理论在轨道

    车辆-轨道耦合动力学理论在轨道,高建敏,翟婉明,提出了将车辆-轨道耦合动力学理论引入轨道下沉变形研究的分析方法。通过将车辆-轨道垂向耦合振动模型和轨道累积下沉计算模型相

    EDEM-FLUENT耦合接口2.2版本编译工具.rar

    6. **应用耦合接口**:在实际项目中,用户需要将EDEM的颗粒系统和FLUENT的流体域结合起来,设置合适的边界条件和耦合参数,然后运行模拟。 这个过程可能涉及到高级编程和计算流体动力学的知识,对于非专业用户可能...

    GSD文件-V2.35-PNPN耦合器.rar

    标题中的"GSD文件-V2.35-PNPN耦合器.rar"暗示了这是一个关于电子工程领域的技术资料,特别是涉及到半导体器件的PNPN耦合器。GSD文件通常指的是Gerber Software Data,这是一种用于电子制造行业的图形数据格式,用于...

    EDEM-Fluent耦合接口2.2版本编译与应用.pdf

    《EDEM-Fluent耦合接口2.2版本编译与应用》 EDEM-Fluent耦合接口是用于模拟离散相(DPM)和连续相(CFD)之间相互作用的一种高级工具,它结合了EDEM(离散元素法软件)和Fluent(流体动力学软件)的优点,为多相流动...

    Simpack车桥耦合模型系列教学视频 车-轨-桥耦合教程 刚-柔耦合教程 可单独 主要涉及软件:ABAQUSSIMPACK 都

    Simpack车桥耦合模型系列教学视频 车-轨-桥耦合教程 刚-柔耦合教程 可单独 主要涉及软件:ABAQUSSIMPACK 都是学生,内容绝对超值,为大家节省学习时间,后期大家可以共同交流。 :1.SIMPCK2021+SIMPACK2021x的安装包...

    深部开采工程中渗流-损伤-应力耦合模型

    为了研究地应力场、损伤对渗流场深部岩体的影响问题,从理论上分析了岩体渗流运动的基本规律,引入岩体变形过程中应力、损伤与透气性演化的耦合作用方程,建立了含岩体开挖过程固气-损伤耦合作用模型。应用该模型模拟...

    EDEM-CFD耦合

    ### EDEM-CFD耦合详解 #### 背景 EDEM-CFD耦合技术是将离散元素方法(DEM)与计算流体力学(CFD)相结合的一种高级模拟技术。这种耦合允许用户在仿真过程中同时考虑固体颗粒的行为及其与周围流体介质之间的相互...

    EDEM-FLUENT耦合接口.rar

    此文件为EDEM与ANSYS FLUENT耦合接口文件,其中分别有ANSYS18.0与EDEM2018.2;ANSYS18.1与EDEM2018.2;ANSYS18.2与EDEM2018.2;ANSYS19.0与EDEM2018.2;ANSYS19.2与EDEM2018.2。解压后可用记事本打开README.LINUX,依照...

    marc热-机耦合分析

    #### 七、总结 热-机耦合分析在现代工程设计和分析中扮演着重要角色。通过合理选择耦合类型、准确设置边界条件和初始条件,可以有效模拟结构在复杂环境下的行为。MSC.Marc和Patran等工具为工程师提供了强大的技术...

    具有任意夹角的微带-槽线耦合过渡的网络分析

    微带-槽线耦合过渡的网络分析 微带-槽线耦合过渡是微波和毫米波电路中的一种常见结构,用于实现微带线和槽线之间的电磁场耦合。传统的分析方法存在一些限制,例如只能用于直角过渡、精度有限等。为此,本文提出了一...

Global site tag (gtag.js) - Google Analytics