面向对象设计原则之 - 低耦合

待兔 等级 768 0 0
标签:

耦合到底是什么?

耦合(或者称为依赖)是程序模块之间的依赖程度。

从定义上看,耦合和内聚是相反的:

  • 内聚关注模块内部的元素的结合程度

  • 耦合关注模块之间的依赖程度

理解耦合的关键有两点:

  • 什么是模块?

    模块和内聚里面提到的模块是一样的,耦合中的模块其实也是可大可小的。

    常见的模块有函数,类,包,子模块,子系统等

  • 什么是依赖?

    依赖这个词很好理解,通俗地讲,就是某个模块用到了另一个模块的一些元素,元素可大可小。

    比如一个类的元素有成员变量,方法,静态变量等

    例如, A 类使用了 B 类作为参数,在 A 类的函数中使用了 B 类来完成某些功能...

耦合的分类 ?

参考维基百科,耦合有 8 种,以下各种形式的耦合,其耦合程度越来越高

1 无耦合

无耦合意味着模块之间没有任何关联或者交互

有的人认为无耦合就是最好的,但其实不然。完成没有耦合意味着一个模块完全不依赖任何其它模块

如果这个模块是非常底层的模块,那么没有什么问题

但如果这个模块完全自给自足,什么事情都自己做,那么就得不偿失了。

完全无耦合的模块虽然不受其它模块的影响,但同时也失去了重用其它模块的机会

每个轮子都要自己发明,这样的效率低下。

就像一个人与世隔绝一样,什么东西都要自给自足,不能利用分工合作。

例如,我们要设计一个学生管理的类 StudentManager ,在正常情况下这样的类一般会依赖 数据库操作 DAO类日志记录Logger类

但其实我们完全可以设计一个无耦合的 StudentManager 类,直接使用 JDBC 操作数据库,使用文件 API 记录日志。

样例代码如下:

/**
 * 完全无耦合的类的设计
 * 使用 JDBC 操作数据库,使用文件 API 记录日志
 * 只以 add 操作为例,其它的 update,delete,get操作类似
 * 欢迎关注 HelloWorld 开发者社区 【 www.helloworld.net 】
 */
public class StudentManager {

    public void add(int studentId, String name){
        //使用自己的私有方法操作数据库
        dbInsert(studentId,name);

        //使用自己的私有方法记录日志
        log("ERROR","add a student");
    }

    //不使用DAO类,直接用JDBC操作数据库
    private void dbInsert(int studentId, String name){
        //省略具体代码实现
    }

    //不使用log4j之类的日志库,自己打开日志文件写日志
    private void log(String level,String message){
        //省略具体代码实现
    }
}

2 消息耦合

消息耦合,即模块之间的耦合关系表现在消息传递上。如下图

面向对象设计原则之 - 低耦合

这里的消息随着模块的不同而不同。

例如:

系统与子系统 : 两个系统的交互接口,比如 HTTP 接口,Java RPC 接口等

类与类的消息:比如 A 类的方法调用了B 类的某个方法,这个方法就是消息

消息耦合是一种耦合程度很低的耦合,是比较理想的耦合,因为调用方仅仅依赖被调用方的消息

即不需要传递参数,也不需要了解被调用方的内部逻辑,更不需要控制调用方内部的逻辑

我们以 人开车这个场景为例,代码如下:

public class Car {
    public void drive(){
        //省略具体实现
    }
}
public class Person {
    public void driveCar(Car car){
        car.drive(); //消息耦合
    }
}

3 数据耦合

两个模块间通过参数传递基本数据,称为数据耦合

如下图:

面向对象设计原则之 - 低耦合

这里有 2 点需要特别关注,这也是数据耦合区别于其它耦合类型的关键特征

  • 通过参数传递,而不是通过全局数据,配置文件 ,共享内存等其它方式
  • 传递的参数是基本数据类型,而不是数据结构,基本类型有:比如在Java中,有 Integer , double , String等类型

在下例例子中, Teacher 类和 Student 类的耦合就是数据耦合

public class Student {
    /**
     * 学号
     * 这就是数据耦合的地方
     */
    public int studentId;

    public String getName(int studentId){
        //根据 studentId查询数据库,获取学生的姓名,具体代码省略
        String name = "待兔";
        return name;
    }

    public int getRank(int studentId){
        //根据 studentId查询数据库,获取学生的排名,具体代码省略
        int rank = 1;
        return rank;
    }
}
public class Teacher {
    public void printStudentRank(int studentId){
        Student student = new Student();

        // Teacher 依赖 Student 类,通过参数传递类型为 int 的基础数据 studentId
        String name = student.getName(studentId);
        int rank = student.getRank(studentId);

        System.out.println("姓名:" + name + "  排名:" + rank);
    }
}

4 数据结构耦合

两个模块通过传递数据结构的方式传递数据,称为数据结构耦合,又称为标签耦合。

个人觉得数据结构耦合 能更好的理解意思

如下图:

面向对象设计原则之 - 低耦合

数据结构耦合数据耦合 是比较相近的,主要差别在于数据结构耦合 中传递的不是 基本数据 , 而是数据结构

另外需要注意的是:数据数据中的成员数据并不是每一个都用到,可以只用其中一部分。

在如下样例中, Teacher 类和 Student 类的耦合就是数据结构耦合,且只用到了 StudentInfo.id 这个字段

代码示例如下:

public class StudentInfo {
    public String name;
    public int id;
    public int rank;
}
public class Student {
    /**
     * @param info 学生信息,这里就是数据耦合的地方
     * @return
     */
   public String getName(StudentInfo info){
       //只用到了 id ,StudentInfo其它的字段并没有用到
       return getNameById(info.id);
   }

    /**
     * @param info 学生信息,这里就是数据耦合的地方
     * @return
     */
   public int getRank(StudentInfo info){
       //只用到了 id ,StudentInfo其它的字段并没有用到
       return getRankById(info.id);
   }

   private String getNameById(int studentId){
       String name = "tom";
       //查询数据库,获取学生姓名,这里省略具体实现

       return name;
   }

   private int getRankById(int studentId){
       int rank = 1;
       //查询数据库,获取学生排名,这里省略具体实现

       return rank;
   }
}

5 控制耦合

当一个模块可以通过某种方式控制另一个模块的行为时,称为控制耦合

如下图:

面向对象设计原则之 - 低耦合

是常见的控制方式就是通过传入一个控制参数来控制函数的处理流程或者输出,例如常见的工厂类

/**
 * 生产手机的工厂类
 */
public class PhoneFactory {
    public String producePhone(int type){
        if (type == 100) {
            return "小米手机";
        } else if (type == 200) {
            return "华为手机";
        } else if (type == 300) {
            return "苹果手机";
        } else {
            return "其它手机";
        }
    }
}

6 外部耦合

当两个模块依赖相同的外部数据格式,通信协议,设备接口时,称为外部耦合

如下图:

面向对象设计原则之 - 低耦合

理解外部耦合的关键在于:为什么叫 “外部” ?

这里的外部当然是与 内部 相对应的,比如前面我们提到的各种耦合方式,可以都认为是内部耦合

因为这些耦合都是由模块内部来完成的。但是在外部耦合的场景下,两个模块对其它模块没有直接的感知

两个模块之间也没有直接的交互,而是通过约定的协议格式 ,接口 等完成分工合作

典型的外部耦合,其实我们时时都能看到,那就是操作系统和外设之间的耦合 。

例如,操作系统和 USB鼠标,这里的 USB 就是一个标准接口,操作系统接收 USB 的输入信号

而鼠标按照 USB 的接口的输出信号 ,如下图

面向对象设计原则之 - 低耦合

7 全局耦合

当两个模块共享相同的全局数据时,称为全局耦合

如下图:

面向对象设计原则之 - 低耦合

全局耦合是一种比较常见的耦合方式,例如 C/C++程序的全局变量,JAVA中的单例变量等

8 内容耦合

当一个模块依赖另一个模块的内部内容时,称为内容耦合

内容耦合是最差的一种耦合方式,因此它有一个形象的名称:病态耦合

面向对象设计原则之 - 低耦合

内容耦合是最差的一种耦合方式,因为内容耦合完全破坏了模块的封装性。

处于内容耦合的两个模块,就像是一条绳上的蚂蚱,没有办法单独修改或者优化

如上图中所示:B模块想要修改内容,是不能独立修改的,因为修改会影响 A 模块

即使改个名称也要一起改

最常见的内容耦合的例子就是某个类有一个public的成员变量,然后其它类直接使用这个成员变量

示例代码如下:

public class Victim {    public int money = 100; //其它类可以直接访问这个"内容",包括 "小偷" 类 Thief        public void makeMoney(int m){        money += m;    }}
public class Thief {    public void stolenMoney(Victim victim){        victim.money -= 100; //内容耦合,小偷可以直接将钱 减去 100    }}

在上面这个代码样例中,如果 Victim 类想将 money 改名为 myMoney ,那么是不能单独修改的,Thief类需要同步修改才可以。

小结

上以就是相关耦合的内容,我们的目的是追求低耦合。下面对本章的内容小小的总结一下:

耦合(或者称为依赖)是程序模块之间的依赖程度。

从定义上看,耦合和内聚是相反的:

  • 内聚关注模块内部的元素的结合程度

  • 耦合关注模块之间的依赖程度

理解耦合的关键有两点:

  • 什么是模块?

    模块和内聚里面提到的模块是一样的,耦合中的模块其实也是可大可小的。

    常见的模块有函数,类,包,子模块,子系统等

  • 什么是依赖?

    依赖这个词很好理解,通俗地讲,就是某个模块用到了另一个模块的一些元素,元素可大可小。

    比如一个类的元素有成员变量,方法,静态变量等

    例如, A 类使用了 B 类作为参数,在 A 类的函数中使用了 B 类来完成某些功能...

耦合有以下几种分类:

  • 无耦合
  • 消息耦合
  • 数据耦合
  • 数据结构耦合
  • 控制耦合
  • 外部耦合
  • 全局耦合
  • 内容耦合
收藏
评论区

相关推荐

2B 领域下的低代码探索之路
前言 大家好,我是钉钉宜搭前端一个小团队的负责人,在阿里做了五年的低代码。今天的分享我们不讲技术细节,主要会分享下我们这五年的探索过程和当前的市场分析,希望能给大家带来一个对低代码搭建不一样视角的认识。 什么是低代码 说起低代码(LowCode)这个词,是在 2014 年,Forrester Research 第一次正式使用低代码来描述这个市场
C语言深入学习系列
用C语言写程序时需要知道是大端模式还是小端模式。 所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;所谓的**小端模式**,是指**数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中**。 为什么会有大小端模式之分呢?这是因为**在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,
Java 类之间的关系
总述 == 类和类之间的关系,耦合度从高到低: * is 。继承、实现 * has 。组合、聚合、关联 * use 。依赖。 要求是:**高内聚、低耦合。** 继承 == Person 和 Man之间是继承关系。 ![](https://oscimg.oschina.net/oscnet/7b9f06e3a37b7bc9c5c2fe14
Java 编译与反编译
##编程语言 在介绍编译和反编译之前,我们先来简单介绍下编程语言(Programming Language)。编程语言(Programming Language)分为低级语言(Low-level Language)和高级语言(High-level Language)。 机器语言(Machine Language)和汇编语言(Assembly Languag
java中的daemon thread
java中的daemon thread java中有两种类型的thread,user threads 和 daemon threads。 User threads是高优先级的thread,JVM将会等待所有的User Threads运行完毕之后才会结束运行。 daemon threads是低优先级的thread,它的作用是为User Thread提供服
1015 德才论 (25)(25 分)
#1015 德才论 (25)(25 分) 宋代史学家司马光在《资治通鉴》中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人。凡取人之术,苟不得圣人,君子而与之,与其得小人,不若得愚人。” 现给出一批考生的德才分数,请根据司马光的理论给出录取排名。 **输入格式:** 输入第1行给出3个正整数,分别为:N
Knative Serverless 之道:如何 0 运维、低成本实现应用托管?
作者 | 牛秋霖(冬岛)  阿里云容器平台技术专家 **关注“阿里巴巴云原生”公众号,回复关键词**\*\*“1205”\*\***即可观看 Knative-Demo 演示视频。** > **导读**:Serverless 无疑是当前最热的云原生话题,那么作为业务的开发人员或者运维人员咱们应该怎么看待这个事情?云原生和 Serverless 到底有什么关
Spring面试,IoC和AOP的理解
spring 的优点? 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦  2.可以使用容易提供的众多服务,如事务管理,消息服务等  3.容器提供单例模式支持  4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能  5.容器提供了众多的辅助类,能加快应用的开发  6.spring对于主流的应用框架提供了集成支
面向对象设计原则之 - 低耦合
耦合到底是什么?耦合(或者称为依赖)是程序模块之间的依赖程度。从定义上看,耦合和内聚是相反的: 内聚关注模块内部的元素的结合程度 耦合关注模块之间的依赖程度理解耦合的关键有两点: 什么是模块? 模块和内聚里面提到的模块是一样的,耦合中的模块其实也是可大可小的。 常见的模块有函数,类,包,子模块,子系统等 什么是依赖? 依赖这个词很好理解,通俗地讲,就是
面对质疑,“ 低代码 ” 站起来了!
近几年,低代码开发成为了行业内的热点。当然,每当一个新事物出现时,总有人对它褒贬不一。有人说,低代码是“毒瘤”现实业务应用的场景极其复杂,不是低代码能解决的;如果低代码面向小白用户,那么最后到底由谁来编写代码?又有人说,低代码帮技术人员减少不必要的技术复杂度以及重复率,使得技术人员重心放在核心的业务逻辑上;低代码的对象并不完全面向入门小白,而是面向业务流程设
飞速低代码|深度解析低代码的奥妙
​全球疫情的爆发,阻断无数人与人之间的物理连接,但却阻挡不了互联网时代的发展。你是否在思考:后疫情时代,究竟什么样的新技术,才能真正解放IT生产力,加速社会数字化转型?小飞认为是低代码LowCode。它凭借着高生产力、降本增效、平民化的独特优势,成为了众多企业实现或加速数字化转型的重要手段之一。(图片来源于:网络) PART 01 什么是低代码?绝不是代码很
飞速低代码:低代码,真神器还是伪风口?
​ 开发者:听说你能让我们告别 996 ? 引用低代码:试试就知道!如果一个概念能在科技圈火起来,它往往兼具字面简明和内涵丰富的特征,并具有某种重塑产业格局的潜力。低代码(Low Code)就是这样一个典型。顾名思义,低代码是指少用代码,甚至不用代码,仅通过拖拽模块的方式实现应用开发。2021 年以来,低代码成为智能产业圈的一大热词。不仅阿里、腾讯、百度等互
飞速企业级低代码 | 低代码市场火热:是 IT 革命还是高级外包
​低代码,一种快速开发应用的软件,将通用、可重复利用的代码形成组件化的模块,通过图形化的界面来拖拽组件并形成应用。低代码能够实现只写少量代码或不写代码,类似用“乐高积木”的方式来开发。在国外有很多著名的低代码成功案例。Outsystems 帮助施耐德电气在 20 个月内推出了 60 款应用程序,开发过程加速了两倍,仅在第一年就节省了 650 人天的工作量;在
企业级飞速低代码开发平台 | 低代码并不意味着低风险
在过去的几年中,低代码和无代码工具以及平台在企业中兴起。2021年,Gartner魔力象限在关于低代码的报告中指出,41%的非IT从业人员使用低代码/无代码工具来定制、构建数据,或提出技术解决方案。同时Gartner预测到2025年底,将有一半的新增低代码用户来自从事非IT 行业的商业客户。​低代码/无代码工具提供支持拖放的交互界面,使得即使非程序员也能够创
灵魂发问:低代码真的会使程序过于复杂吗?
低代码继续受到大量关注和争论。许多软件开发人员仍然想知道使用低代码是否会使应用程序开发过程更好,或者它是否会干扰开发过程并导致劣质应用程序。其他人则担心低代码的安全隐患。当然,如果使用低代码的必然结果是更高的应用程序复杂性,那么低代码可能会导致安全问题的难度增加。但真的是这样吗?我最近写了很多关于应用程序复杂性的文章,还有很多关于低代码的文章。但是应用程序复