详解C/C++中低耦合代码的设计实现

Finn
Finn
发布时间:2026-10-16 | 5人浏览过
原创

在C/C++开发中,模块间相互依赖是引发代码僵化和维护困难的常见原因。本文针对类间环依赖、函数调用耦合等典型场景,提供从基础修复到高级架构优化的完整解决方案。

消除类间环依赖的方法

在设计面向对象系统时,有时需要两个类或模块相互“认识”,例如网店系统中的客户类(Customer)与账户类(Account)。这种直接的互相引用会导致UML中的环依赖问题:

开发者常采用结构体或类前置声明来解决编译错误。

customer.h

#ifndef CUSTOMER_H_
#define CUSTOMER_H_
 
class Account;
class Customer
{
   // ...
   void setAccount(Account* account);
   {
       customerAccount = account;
   }
  //...
private:
   Account* customerAccount;
};
#endif

account.h

#ifndef ACCOUNT_H_
#define ACCOUNT_H_
class Customer;
class Account
{
 public:
      //...
     void setOwer(Customer* customer)
     {
           ower = customer;
     }
   //...
  private:
         Customer* ower;
}
#endif

虽然上述方式能消除编译器的报错,但这种方案并不完美。以下调用示例展示了其致命隐患:

#include "account.h"
#include "customer.h"
 
//...
Account *account = new Accout{};
Customer *customer = new Customer{};
account->setOwer(customer);
customer->setAccount(account);

当删除 Account 实例时,Customer 实例仍会存在,但其内部指向 Account 的指针变为悬垂指针(空指针或未初始化状态)。此时使用或解引用此指针将导致严重的问题,如段错误或数据损坏。

应用依赖倒置原则

依赖倒置原则(DIP)能有效解决此类强耦合问题。核心思想是不让两个具体类直接访问对方,而是只通过抽象接口进行交互。

第1步:定义抽象接口

首先提取公共接口。以从 Customer 中提取的 Owner 为例,在该接口中声明纯虚函数,强制子类必须覆盖它:

ower.h

#ifndef OWNER_H_
#define OWNER_H_
 
#include <memory>
#include <string>
 
class owner
{
   public:
       virtual ~owner()=default;
       virtual std::string getName() const = 0;
};
using OwnerPtr = std::shared_ptr<Owner>;
#endif

第2步:实现业务类继承接口

Customer.h

#ifndef CUSTOMER_H_
#define CUSTOMER_H_
 
#include "Owner.h"
#include "Account.h"
 
class Customer:public Owner
{
  public:
     void setAccount(AccountPtr account)
     {
            customerAccount =   account;    
     }
  virtual std::string getName() const override{
    //return string
  }
 
  private:
     Account customerAccount;
};
using CustomerPtr = std::shared_ptr<Customer>;
#endif

第3步:重构类之间的关联

account.h

#ifndef ACCOUNT_H_
#define ACCOUNT_H_
 
#include "Owner.h"
class Account
{
   public:
       void setOwner(OwnerPtr owner)
       {
          this->owner = owner;
       }
   private:
      OwnerPtr owner;
};
using AccountPtr = std::shared_ptr<Account>;

经过上述重构后,Customer 和 Account 之间消除了直接的环依赖,它们仅依赖于抽象接口 Owner,从而实现了松耦合设计。

降低功能耦合性:回调函数与信号槽

对于非面向对象的功能模块,我们通常采用回调函数或者信号槽的方式来联系两个模块,以降低功能代码的耦合度。

使用回调函数解耦

通过函数指针,可以将功能的执行权交给调用者,被调模块只需负责逻辑处理,而不需关心调用方的具体实现。

a.h (功能模块A声明)

#pragma once
#ifndef A_H_
#define A_H_
#include <stdio.h>
 
 
int test(int c);
 
#endif

a.c (功能模块A实现)

#include "a.h"
int test(int c)
{
    c = 0x11112;
    return c;
}

b.h (调用模块B声明)

#pragma once
#ifndef B_H_
#define B_H_
#include <stdio.h>
 
typedef int (*PtrFunA)(int);
 
int testb(PtrFunA, int c);
#endif

b.c (调用模块B实现)

#include "b.h"
 
int testb(PtrFunA a, int c)
{
    int ret = a(c);
    printf("%d\n", ret);
    return ret;
}

main.c (入口文件)

#include <stdio.h>
#include "a.h"
#include "b.h"
int main()
{
    testb(test,123);
}

这样做的好处是将A模块的功能代码完全封装在 a.c 中,B模块的功能代码只写在 b.c 中。为进一步增强通用性,改进后的回调函数可以使用 void* 进行传参,在 a.c 中对 void* 类型进行判断,这是许多底层库常用的操作模式。

信号槽机制

相比回调函数,信号槽机制更加灵活,代码的耦合度更低。但由于其实现较为复杂(通常涉及宏或特定的事件分发框架),在实际项目中建议优先使用成熟的第三方库或现代C++特性实现,此处暂不展开具体代码实现细节。

以上就是详解C/C++中低耦合代码的设计实现的详细内容,更多关于C++低耦合代码的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表