MST

星途 面试题库

面试题:C++设计模式与可维护性的关联

阐述在C++项目中,单例模式、策略模式和观察者模式分别在哪些场景下能显著提高代码的可维护性,详细说明其原理以及在代码实现上如何体现可维护性。
39.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

单例模式

  • 适用场景:在整个应用程序中,某个类的实例只需要存在一个,例如数据库连接池、日志记录器等场景。
  • 原理:保证一个类仅有一个实例,并提供一个全局访问点。通过将构造函数设为私有,防止外部直接创建实例,使用静态成员函数来控制实例的创建和访问。
  • 代码实现体现可维护性:例如在数据库连接池单例中,后续若要修改连接池的初始化逻辑,只需在单例类的内部修改,不会影响到其他使用连接池的地方。因为所有对连接池的访问都通过单例类的全局访问点,一处修改,到处生效。
class Singleton {
private:
    static Singleton* instance;
    Singleton() {}
    ~Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};

策略模式

  • 适用场景:当有多种算法或行为可以选择,且在运行时需要动态切换时,例如不同的排序算法、不同的支付方式等。
  • 原理:定义一系列算法,将每个算法封装起来,使它们可以相互替换。通过将算法封装成独立的类,让这些类实现相同的接口,客户端可以根据需要选择不同的策略类。
  • 代码实现体现可维护性:以不同排序算法为例,如果新增一种排序算法,只需创建一个新的策略类实现相应接口,而无需修改原有排序算法的代码和使用排序功能的客户端代码。客户端只关心接口,不关心具体实现。
class SortStrategy {
public:
    virtual void sort(int* arr, int n) = 0;
};

class BubbleSort : public SortStrategy {
public:
    void sort(int* arr, int n) override {
        // 冒泡排序实现
    }
};

class QuickSort : public SortStrategy {
public:
    void sort(int* arr, int n) override {
        // 快速排序实现
    }
};

class Sorter {
private:
    SortStrategy* strategy;
public:
    Sorter(SortStrategy* s) : strategy(s) {}
    void sortArray(int* arr, int n) {
        strategy->sort(arr, n);
    }
};

观察者模式

  • 适用场景:当一个对象的状态发生变化时,需要自动通知其他多个对象,例如图形界面中的事件监听、消息推送系统等。
  • 原理:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。被观察对象(主题)维护一个观察者列表,当状态改变时,遍历列表通知所有观察者。
  • 代码实现体现可维护性:例如在消息推送系统中,如果新增一种类型的消息接收者(观察者),只需创建新的观察者类实现相应接口并注册到主题中,不会影响主题和其他观察者的代码。主题只负责通知,不关心具体观察者的行为。
#include <vector>
#include <iostream>

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

class Subject {
private:
    std::vector<Observer*> observers;
public:
    void attach(Observer* o) {
        observers.push_back(o);
    }
    void detach(Observer* o) {
        for (auto it = observers.begin(); it != observers.end(); ++it) {
            if (*it == o) {
                observers.erase(it);
                break;
            }
        }
    }
    void notify() {
        for (Observer* o : observers) {
            o->update();
        }
    }
};

class ConcreteObserver : public Observer {
private:
    Subject* subject;
public:
    ConcreteObserver(Subject* s) : subject(s) {
        subject->attach(this);
    }
    ~ConcreteObserver() {
        subject->detach(this);
    }
    void update() override {
        std::cout << "ConcreteObserver updated" << std::endl;
    }
};