如何实现代码的高内聚低耦合

30 篇文章 1 订阅

之前在参加宋宝华老师的培训时,宋老师经常说写代码要做到高内聚低耦合,当时并不太理解其意义,只是感觉这句话是正确的,但是不知道具体如何操作,后来代码写的看的多了,才初窥门径,下面就是自己的一点经验总结。


一 高内聚低耦合含义

写代码时,一般会划分模块,模块内,要做到高内聚,而模块之间则要低耦合,这样可使代码的模块化更好,提高了可重用性和可移植性。

道理很好理解。


二 举例

1. 使用头文件

假设我们有个模块叫func,其代码全部放在func目录下,其结构如下,
在这里插入图片描述
这个模块对外接口都放在func.h里,而具体实现代码则是放在src目录下的文件里。func模块的功能就是提供了一个func函数,func.h如下,

#ifndef _FUNC_H_
#define _FUNC_H_

int func(void);

#endif

别的代码要使用这个func模块,只要直接包含这个头文件就可以了,而不用去关心模块内部的实现细节,也不用去包含这些实现文件

func.c内容如下,

#include "aa.h"
#include "bb.h"


int func(void)
{
    return 50 + helper_aa(50) + helper_bb(50);
}

aa.h和aa.c内容如下,

// aa.h
#ifndef _AA_H_
#define _AA_H_

int helper_aa(int data);

#endif
// aa.c
int helper_aa(int data)
{
    return data * 10;
}

bb.h和bb.c的内容如下,

// bb.h
#ifndef _BB_H_
#define _BB_H_

int helper_bb(int data);

#endif
// bb.c
int helper_bb(int data)
{
    return data * 20;
}

假如我们现在有个main.c,里面要使用func模块的功能,main.c的内容如下,

// main.c
#include <stdio.h>
#include "func.h"

int main(void)
{
    int data = func();
    printf("data from func: %d\n", data);
    
    return 0;
}

这样对于main()函数来说,它能看到的仅仅是func.h头文件里的函数声明,而func模块内部的实现细节它一点都不需要关心。
这样就做到了高内聚和低耦合。高内聚是指func模块的实现都在模块内部,外部看不到也不需要关心,当func模块的实现代码需要修改时,调用者代码不需要重新编译。低耦合是指其它模块或者函数需要使用func模块功能时,只用包含func.h这个头文件就可以了。

同理,也可以把main函数想象成别的模块使用func模块提供的功能。

2. 使用前置声明

使用前置声明也可以实现高内聚低耦合,甚至不用包含接口头文件,下面就来看下如何操作的。

假如我们有个叫func的模块,其结构体如下,
在这里插入图片描述
func.h内容如下,

#ifndef _FUNC_H_
#define _FUNC_H_

struct FuncData {
    int data1;
    int data2;
};

// 分配一个struct FuncData变量
struct FuncData * newFuncData(void);

// 增加struct FuncData里的成员变量值
void increaseFuncData(struct FuncData *ptr);

// 打印struct FuncData里的成员变量值
void printCurrentValue(struct FuncData *ptr);

#endif

func.c内容如下,

#include <stdlib.h>
#include <stdio.h>
#include "func.h"

struct FuncData * newFuncData(void)
{
    return new calloc(1, sizeof(struct FuncData));
}

void increaseFuncData(struct FuncData *ptr)
{
    ptr->data1 += 10;
    ptr->data2 += 20;
}

void printCurrentValue(struct FuncData *ptr)
{
    printf("data1 of FuncData: %d\n", ptr->data1);
    printf("data2 of FuncData: %d\n", ptr->data2);
}

这时我们有个main.c,会调用这个func模块里的功能,其代码如下,

#include <stdio.h>

struct FuncData; // 前置声明

struct FuncData * newFuncData(void);

void increaseFuncData(struct FuncData *ptr);

void printCurrentValue(struct FuncData *ptr);


int main(void)
{
    struct FuncData *ptr = newFuncData();
    if (ptr == NULL)
    {
        printf("Error in newFuncData()\n");
        return -1;
    }
    
    increaseFuncData(ptr);
    printCurrentValue(ptr);
    
    return 0;
}

main.c里没有包含func.h,而是使用了前置声明,对于struct FuncData,虽然使用了前置声明,但是其内部成员变量在main.c里是不知道的,术语叫不完整类型,所以只能使用指针,其相关操作函数传递的参数或返回值都是struct FuncData指针,这样才可以让前置声明运行OK。

前置声明可以让我们根据需要挑选需要的模块功能,而不用包含模块的接口头文件,这样可以减少编译量。而且和头文件一样,模块的实现代码发生变化,只要接口不变就不用重新编译调用者的程序。


三 总结

本文主要使用简单代码讲述如何实现代码模块的高内聚和低耦合,这样使得编写的代码结构更加清晰,且更符合软件工程的要求。如果代码量比较小,可能感觉不到带来的好处,但是当工程变得复杂,其优点就会充分体现出来了。

如果有写的不对的地方,希望能留言指正,谢谢阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值