乐于分享
好东西不私藏

从烂代码到软件架构 | 高内聚低耦合

从烂代码到软件架构 | 高内聚低耦合

有这么一个需求,输入员工姓名和工作时长,固定时薪 50 元/小时,然后输出结果。

你写的代码是不是这样的:

#include<stdio.h>intmain(){    char name[20];    int hours;    printf("请输入姓名:");    scanf("%s", name);    printf("请输入工时:");    scanf("%d", &hours);    int salary = hours * 50    printf("员工:%s\n", name);    printf("工资:%d\n", salary);    return 0;}

把所有功能都放在了主函数中,主打一个能跑就行。

这种代码就是典型的烂到家了,如果改改需求,把数据的输入改成从配置文件读取,或者再增加奖金机制,主函数都得改。

这种代码就是低内聚、高耦合,一个模块塞入很多功能,牵一发而动全身。

下面对代码做第一版修改。

既然刚才说所有代码都被塞进了主函数,那就把他们全部封装成函数:

#include<stdio.h>voidinputEmployee(char *name, int *hours){    printf("请输入姓名:");    scanf("%s", name);    printf("请输入工时:");    scanf("%d", hours);}intcalcSalary(int hours){    return hours * 50}voidprintSalary(char *name, int salary){    printf("员工:%s\n", name);    printf("工资:%d\n", salary);}intmain(){    char name[20];    int hours;    inputEmployee(name, &hours);    int salary = calcSalary(hours);    printSalary(name, salary);    return 0;}

获取员工信息、计算薪资、输出结果,每个函数只负责干一件事情,这就是所谓的高内聚。主函数中,也只需要调用对应的函数就行。

但是老板又给出了新的需求:普通员工50/小时,高级员工80/小时。

继续来修改代码,可能你会这样写:

#include<stdio.h>voidinputEmployee(char *name, int *hours){    printf("请输入姓名:");    scanf("%s", name);    printf("请输入工时:");    scanf("%d", hours);}intcalcSalary(int hours, int level){    if(level == 1)        return hours * 50    else        return hours * 80}voidprintSalary(char *name, int salary){    printf("员工:%s\n", name);    printf("工资:%d\n", salary);}intmain(){    char name[20];    int hours;    inputEmployee(name, &hours);    int salary = calcSalary(hours, 1);     printSalary(name, salary);    return 0;}

增加一个判断,不同的员工走不同的分支。

确实能解决问题,但新的问题又来了:等级规则、薪资规则、员工信息又开始纠缠在一起。

第四个版本,开始引入结构体,把员工的信息封装起来,同时计算薪资的函数改成这样。

#include<stdio.h>typedef struct{    char name[20];    int hours;    int level;} Employee;voidinputEmployee(Employee *emp){    printf("请输入姓名:");    scanf("%s", emp->name);    printf("请输入工时:");    scanf("%d", &emp->hours);}intcalcSalary(Employee *emp){    if(emp->level == 1)        return emp->hours * 50    else        return emp->hours * 80}voidprintSalary(Employee *emp, int salary){    printf("员工:%s\n", emp->name);    printf("工资:%d\n", salary);}intmain(){    Employee emp;    inputEmployee(&emp);    int salary = calcSalary(&emp);    printSalary(&emp, salary);    return 0;}

主函数,也都围绕结构体展开。

这个设计确实不错,员工的数据放在结构体里面统一管理。

但是不省心的老板又提出了新的需求,岗位不仅有普通员工、高级员工,还有经理和总监,是不是还得在函数里面加代码。

不好意思,这就是开闭原则,当需求变化时,你应该通过添加新代码来扩展系统的行为,而不是修改已有的、已经测试过的代码。本来好好的代码,被你一改,又要重新测试。

最后,不得不拿出杀手锏,在结构体里面定义函数指针:

#include<stdio.h>typedef struct{    char name[20];    int hours;    int (*calc)(int h); } Employee;voidinputEmployee(Employee *emp){    printf("请输入姓名:");    scanf("%s", emp->name);    printf("请输入工时:");    scanf("%d", &emp->hours);}intnormalSalary(int hours){    return hours * 50}intseniorSalary(int hours){    return hours * 80}intmanagerSalary(int hours){    return hours * 120;}intcalcSalary(Employee *emp){    return emp->calc(emp->hours);}voidprintSalary(Employee emp, int salary){    printf("员工:%s\n", emp.name);    printf("工资:%d\n", salary);}intmain(){    Employee emp;    inputEmployee(&emp);    emp.calc = managerSalary;    int salary = calcSalary(&emp);    printSalary(emp, salary);    return 0;}
为每一个岗位都单独写一个计算薪资的函数,对于不同的岗位,只要赋值不同的函数就行,就算再增加新的岗位,只要多写个函数就行,原有的代码,一行不改。

所以,什么高内聚、低耦合?高内聚,就是模块内的东西都紧密相关,共同完成一个明确的目标。在函数层面,就是“一个函数只做一件事”。低耦合就是模块之间相互影响甚少,只通过稳定的接口交流,换一个模块就像换一块积木,不影响其他积木。

 《嵌入式AIoT全栈开发课程》 
四个月 从零基础到斩获高薪OFFER
品牌宣传 企业培训 | 技术推广 | 职业提升
请在公众号后台回复 合作