C++面试:代码耦合的产生原因和规避方法

发布时间:2024年01月12日

????????代码耦合是指不同模块间的相互依赖程度。高耦合通常被视为不良的设计,因为它会导致代码难以理解、维护和扩展。了解代码耦合的产生原因和规避方法是软件开发中的一个重要方面,并且这也是面试中常见的话题。

目录

产生原因

全局变量的过度使用

模块间的直接交互

缺乏抽象

改动导致连锁反应

复杂的继承结构

缺乏模块化设计

规避方法

面试准备


产生原因

全局变量的过度使用

全局变量被多个模块共享,导致模块间的隐性依赖。

// 全局变量
int globalCounter;

class ModuleA {
public:
    void increment() {
        globalCounter++; // 直接修改全局变量
    }
};

class ModuleB {
public:
    void print() {
        std::cout << "Counter: " << globalCounter << std::endl; // 直接读取全局变量
    }
};

模块间的直接交互

一个模块直接调用另一个模块的函数或方法。

class ModuleA {
public:
    void doSomething() {
        // 直接调用 ModuleB 的功能
        ModuleB b;
        b.performAction();
    }
};

class ModuleB {
public:
    void performAction() {
        std::cout << "Performing Action" << std::endl;
    }
};

缺乏抽象

具体实现而不是接口被用于模块间的交互。

class SpecificDatabase {
public:
    void connect() {
        // 连接到特定数据库的实现
    }
};

class Application {
    SpecificDatabase db;

public:
    void start() {
        db.connect(); // 直接依赖具体的数据库实现
    }
};

改动导致连锁反应

修改一个模块需要修改其他多个模块。

class ModuleA {
public:
    void action() {
        // ModuleA 的行为
    }
};

class ModuleB {
public:
    void change() {
        ModuleA a;
        a.action(); // 依赖于 ModuleA 的具体行为
        // 任何对 ModuleA 的更改都可能需要修改 ModuleB
    }
};

复杂的继承结构

过度或不当使用继承,使得子类与父类高度耦合。

class Base {
public:
    virtual void operation() = 0;
};

class DerivedA : public Base {
public:
    void operation() override {
        // 实现细节
    }
};

class DerivedB : public Base {
public:
    void operation() override {
        // 实现细节,可能与 DerivedA 高度耦合
    }
};

缺乏模块化设计

没有明确的模块边界,导致代码功能混杂。

class ComplexModule {
public:
    void doTaskA() {
        // 任务 A 的实现
    }

    void doTaskB() {
        // 任务 B 的实现
    }

    // 其他多个功能,使得类过于庞大和复杂
};

规避方法

使用接口和抽象类:定义清晰的接口,使得模块之间基于抽象而不是具体实现进行交互。

class IDatabase {
public:
    virtual void connect() = 0;
};

class MySQLDatabase : public IDatabase {
public:
    void connect() override {
        // MySQL数据库的连接实现
    }
};

class Application {
    IDatabase* db;

public:
    Application(IDatabase* database) : db(database) {}

    void start() {
        db->connect();
    }
};

依赖注入:通过依赖注入的方式来减少模块间的直接依赖。通过构造函数实现。

class Engine {
public:
    void start() {}
};

class Car {
    Engine* engine;
public:
    Car(Engine* e) : engine(e) {}
    void start() { engine->start(); }
};

单一职责原则:每个模块只负责一项功能,有助于降低耦合。

最少知识原则:一个对象应该尽可能少地了解其他对象(只与直接的朋友通信)。

class Document {
public:
    void print() {}
};

class Printer {
public:
    void printDocument(Document &doc) {
        doc.print();
    }
};

模块化和封装:确保模块具有清晰和严格的边界,封装内部实现。

通过private成员变量和public方法进行封装。

class BankAccount {
private:
    double balance;

public:
    void deposit(double amount) { balance += amount; }
    void withdraw(double amount) { balance -= amount; }
};

避免全局变量:使用局部变量或者类成员变量,减少不必要的全局状态。

使用类成员变量代替全局变量。

class Application {
    int setting;

public:
    void setSetting(int s) { setting = s; }
    int getSetting() const { return setting; }
};

利用设计模式:例如,观察者模式可以用于减少事件发生者和事件处理者之间的耦合。

?观察者模式用于减少耦合。

class Observer {
public:
    virtual void update() = 0;
};

class Subject {
    std::vector<Observer*> observers;
public:
    void addObserver(Observer* o) {
        observers.push_back(o);
    }
    void notifyObservers() {
        for (Observer* o : observers) {
            o->update();
        }
    }
};

class ConcreteObserver : public Observer {
public:
    void update() override {
        // 处理更新
    }
};

面试准备

????????在准备面试时,重点关注代码耦合的概念及其产生原因,比如全局变量的过度使用、模块间的直接交互、缺乏抽象、改动的连锁反应、复杂的继承结构和缺乏模块化设计。为了规避这些问题,熟练掌握使用接口和抽象类、依赖注入、遵循单一职责原则、最少知识原则、模块化和封装、避免全局变量以及利用设计模式(如观察者模式)来降低耦合。在面试中,通过具体代码示例和项目经验展示你如何识别并解决耦合问题,同时展示你对这些原则和实践的深入理解。

文章来源:https://blog.csdn.net/weixin_44120785/article/details/135541867
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。