谈谈系统中的耦合以及从另一个角度来解释姜同学的疑虑

今天姜同学发表了http://www.cnblogs.com/ASPNET2008/archive/2008/08/13/1266942.html   

这篇POST表达了对通过分层设计的概念无法解决系统耦合的问题。在之后andytao同学回复了对姜敏朋友的回复 一文作为回应

我在看回复的时候感觉说得不太透,所以忍不住发此文从另外一个角度来试着为姜同学做一次解答。


首先是从姜同学的疑虑开始。姜同学对分层主要是担心增加了工作量缺起不到消除系统耦合的目的。所以我们首先就来谈谈耦合。

-------------------------------------------------以下内容来至软件工程课本----------------------------------------------------------

在软件工程上,耦合指的是指两个实体相互依赖于对方的一个量度。分为以下几种:

非直接耦合:两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的

数据耦合:一个模块访问另一个模块时,彼此之间是通过简单数据参数 (不是控制参数、公共数据结构或外部变量) 来交换输入、输出信息的。

标记耦合 :一组模块通过参数表传递记录信息,就是标记耦合。这个记录是某一数据结构的子结构,而不是简单变量。

控制耦合:如果一个模块通过传送开关、标志、名字等控制信息,明显地控制选择另一模块的功能,就是控制耦合。

外部耦合:一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。

公共耦合:若一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共耦合。公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等。

内容耦合:如果发生下列情形,两个模块之间就发生了内容耦合

(1) 一个模块直接访问另一个模块的内部数据;

(2) 一个模块不通过正常入口转到另一模块内部;

(3) 两个模块有一部分程序代码重迭(只可能出现在汇编语言中);

(4) 一个模块有多个入口。

---------------------------------------------------以上部分定义来至软件工程课本---------------------------------------------------

举几个简单的例子

void main(string args[])

{

      Console.Write(Console.Read());

}

以上的代码里,Console类的Write方法就和Read方法发生了非直接耦合,这种耦合需要有第三方作为控制方才能发生。

 

假设有一个类Book是一个DTO类(只有属性的类,用来传递数据的类)。如果在数据层提供了BookAccess类由一个Add的方法。那么在逻辑层里面调用

Book b=new Book();

//设值

BookAccess.Add(b);

那么这个时候逻辑层和数据层之间就是发生了标记耦合。

 

假设User类提供了一个Login()方法,方法的定义是

bool Login(string UserName,string Password);

那么如果我们在页面上这么写

User.Login(UserN.Text,PassWd.Text);

那么这个时候登陆页和User类就是发生了数据耦合。

 

如果

void output(bool flag)
{

    if(flag)

    {

           Console.Write("OK!");

    }

    else

    {

           Console.Write("NO!");

     }

}

 那么这个时候调用output方法的时候就和他发生了控制耦合。

 

 如果

public class a

{

    private static string msg;

    public static void main(string args[])

    {

         Read();

         Write();

    }

    private static void Read()

    {

         msg=Console.ReadLine();

    }

    private static void Write()

   {

        Console.Write(msg);

    }

}

这个时候就是外部耦合。


如果在逻辑层里面调用了HttpContext类,那么就是环境耦合了,因为这个DLL和Web环境已经不可分了。

 

Class DAL

{

     public string sql;

     public void ExecSql(string sql)

    {

    }

}

这样子的设计就容易发生内容耦合,本来sql是不该被外界访问的,但是这里可以非法访问,如果访问到了就发生了内容耦合了。

 

 那么在知道了什么是耦合后我们再回到姜同学的疑问。根据我们对耦合的定义来看,耦合是无法被消除的。如果两个模块不存在耦合,那么也说明这两个模块之间就r无法发生互动。

 

我们所需要注意的是,虽然耦合是系统交互的必然结果,但是耦合的方式是有区别的。更具上边的介绍我们可以判断出,标记耦合,数据耦合是ok的,内容耦合是最糟糕的,控制耦合和环境耦合其次。所以我们要尽量使用标记耦合而不是后面糟糕的三种耦合方式。当然控制耦合有的时候是无法避免的,那么就能避免就避免了。

C#里比如还是可以用多态来解决控制耦合的问题。

---------------------------------------------------------我是可爱的分割线----------------------------------------------------------

 

所以我们在回过头来看看分层。分层能不能解决耦合的问题,就要看这个层怎么分,如何分,如何定义两个层次之间的交互界面。

 

 那么如何才能定义良好的交互接口呢?

举个例子

Class AccessDAL

{

     public void AddBook(Book newbook)

    {

        //数据操作的代码;

    }

}

 对于逻辑层来说AddBook方法就是一个界面了(用广义上来说也是接口)。这个接口和逻辑层发生的关系就是标记耦合。这种定义就应该优先于

 public void AddBook(string ISBN,string BookName......);

这类定义,因为标记耦合要比数据耦合要好。当然参数很少的时候其实差不多。

 

最后说说修改数据库表结构的问题。如果数据库表结构都修改了那确实是大问题了。要么前期需求没做到位。如果要适应这样子的要求确实没有什么好办法避免表结构的改变给数据以上的各个层次带来的代码变更的工作量。但是如果采用的第一种标记耦合的定义方式的话,起码调用接口的那部分代码不用改动,接口的定义不用改动,只需要修改DTO类的定义就行了,自然数据层相关的代码需要改动。其余部分的在DTO改动后可以通过VS的重构功能来处理,其实还是能够减少不少工作量得了。

 

 

 

 

 

 

 

 

posted on 2008-08-13 22:22 亚历山大同志 阅读(2016) 评论(10)  编辑 收藏 网摘 所属分类: 随笔

评论

#1楼  2008-08-13 22:34 狼Robot      

楼主强悍.N多耦合都给弄出来了.   回复  引用  查看    

#2楼 [楼主] 2008-08-13 22:44 亚历山大同志      

那些都是把教科书的内容拿出来再加工而已,呵呵   回复  引用  查看    

#3楼  2008-08-14 06:40 金色海洋(jyk)      

原来分层真的没有解决当数据库有变动的时候,如何尽量少的修改代码呀。

说来说去还是说,字段变化了,不对,是实体类发生变化了,那么各个层的代码就不得不做修改。这个是三层最郁闷的地方吧。

出现这种情况的误区,我觉得是太过于面向对象了,每一个表都是一个对象,都要定义一个实体类,这就带来了无穷的隐患,大于有点。

你的思路是定义一个book类,然后实现book的增加、修改等操作。

而我的思路是,把数据库(或者是表)作为一个对象来考虑,然后去实现表的增加、修改。

因为表只有一个,而书这样的对象却有很多很多。

  回复  引用  查看    

#4楼  2008-08-14 06:46 金色海洋(jyk)      

表——表单控件。

因为是信息管理方面的程序,是以数据为中心的,一般数据都是要放在数据库里面的,而数据库一般都提供了强大的数据操作功能。

我们为什么仅仅把数据库当作存储数据的容器呢?

我们为什么要忽略T_SQL的强大呢?

所以我的思路是(信息管理方面的程序):以数据库为主,围绕T_SQL编程。

从现实的世界里面去抽象,我们得到了book,猫、狗,动物这样的类。

那么从数据库的角度去抽象,我们会得到什么呢?我得到了表单控件、分页控件,呵呵。

不多说了,免得有人说我在做广告,呵呵。
  回复  引用  查看    

#5楼  2008-08-14 06:52 金色海洋(jyk)      

对了,说点正题,是不是说,有了两个类,这两个类又有点关联,那么就是耦合了,只是耦合的类型不一样。

那么如果只有一个类呢?是不是就没有耦合了呢?

当然我知道,如果在一个类里面实现全部的功能,那么这个类就会变的相当的巨大,和难以维护。

我们为了更好的维护,更清晰的代码,把一个大类,分成了多个小类,清晰了,好维护了,但是却带来了——耦合。

那么如果一个类可以实现一个功能,而类的内部代码又不是很复杂,也是比较清晰,可维护、可扩展的。

那么这个类还有耦合吗?

类的内部就没有耦合了吧,只是在调用这个类的时候才会出现耦合。

如果这个类足够灵活的话,那么就没有什么问题了吧?
  回复  引用  查看    

#6楼  2008-08-14 08:43 姜敏      

非常谢谢这么多园友为在下解释疑惑,LZ的文章使我对耦合有了一个全新的了解。   回复  引用  查看    

#7楼  2008-08-14 08:52 姜敏      

记的LZ在SSO方面有特别强的经验,希望能够学习下。   回复  引用  查看    

#8楼  2008-08-14 14:07 怪怪      

欢迎LZ回来 :P

而且, 又见Book,感觉很亲切呀 ~   回复  引用  查看    

#9楼 [楼主] 2008-08-14 16:09 亚历山大同志      

@怪怪
经典百年不变   回复  引用  查看    

#10楼  2008-08-14 16:58 赵俊      

Web Service能在三层里面起到什么作用吗?Web Service好像不能返回接口,只能返回实体。   回复  引用  查看    

导航

公告

鉴于很多TX投诉黑色背景杀伤眼球,遂换个容易阅读的

<2008年8月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

与我联系

搜索

 

常用链接

留言簿(30)

我参加的小组

我的标签

随笔分类(84)

随笔档案(83)

相册

朋友的Blog

同事的Blog

最新随笔

积分与排名

最新评论

阅读排行榜

评论排行榜