OOP和软件设计中的五大核心设计原则——SOLID原则

这些原则共同目标是让代码更灵活、可维护、可复用,是设计模式(如工厂、策略模式)的基础理论支撑。


SOLID原则解析与对应实现

1. 单一职责原则 (SRP)
  • 原则:一个类只负责一个功能。
  • 核心思想:一个类应该只有一个引起它变化的原因(即只负责一项功能)。
  • 通俗解释
    就像一个人只专注做一件事(例如厨师只管烹饪,服务员只管点餐),避免"万能类"导致代码难以维护。
  • 应用
    • QListWidget 仅负责显示列表项。
    • QScroller 仅负责处理滚动逻辑。
    • 参数配置单独封装(如setupInertialScroll函数)。
cpp 复制代码
// 职责分离:配置惯性滚动的逻辑单独封装
void setupInertialScroll(QAbstractScrollArea *scrollArea) {
    QScroller::grabGesture(scrollArea->viewport(), QScroller::TouchGesture);
    
    QScroller *scroller = QScroller::scroller(scrollArea->viewport());
    QScrollerProperties properties;
    properties.setScrollMetric(QScrollerProperties::DecelerationFactor, 0.2);
    scroller->setScrollerProperties(properties);
}

// 主函数仅负责组装
int main() {
    QListWidget listWidget;
    setupInertialScroll(&listWidget); // 配置滚动逻辑
    // ... 添加列表项
}

2. 开闭原则 (OCP)
  • 原则:对扩展开放,对修改关闭。
  • 核心思想 :软件实体(类、模块等)应对扩展开放 ,对修改关闭
  • 通俗解释
    就像乐高积木------通过添加新积木(扩展)来构建新功能,而不是拆掉旧积木(修改原有代码)。
  • 应用
    • 通过继承或组合扩展滚动行为,而非修改现有类。
    • 示例:自定义SmoothScrollArea类,继承QScrollArea并内置惯性逻辑。
cpp 复制代码
class SmoothScrollArea : public QScrollArea {
public:
    explicit SmoothScrollArea(QWidget *parent = nullptr) : QScrollArea(parent) {
        QScroller::grabGesture(viewport(), QScroller::TouchGesture);
        QScrollerProperties properties;
        properties.setScrollMetric(QScrollerProperties::DecelerationFactor, 0.2);
        QScroller::scroller(viewport())->setScrollerProperties(properties);
    }
};

// 使用扩展类,而非直接修改QScrollArea
SmoothScrollArea scrollArea;

3. 里氏替换原则 (LSP)
  • 原则:子类必须能替换父类且行为一致。
  • 核心思想:子类必须能够替换父类,且不破坏程序的正确性。
  • 通俗解释
    "鸭子类型"------如果它走路像鸭子、叫声像鸭子,那它就应该能当鸭子用。子类不能违背父类的行为约定。
  • 应用
    • SmoothScrollArea继承QScrollArea,确保所有父类方法仍有效。
    • 避免重写核心方法(如event()),除非明确需要修改行为。
cpp 复制代码
// 正确:子类不破坏父类行为
bool SmoothScrollArea::event(QEvent *event) {
    if (event->type() == QEvent::Scroll) {
        // 处理滚动事件,但不影响其他事件
    }
    return QScrollArea::event(event); // 确保父类逻辑仍执行
}

4. 接口隔离原则 (ISP)
  • 原则:客户端不应依赖不需要的接口。
  • 核心思想:客户端不应被迫依赖它不需要的接口。
  • 通俗解释
    就像点餐时只选自己吃的菜,而不是被迫接受一份固定套餐(包含不需要的功能)。
  • 应用
    • 若需要更灵活的滚动控制,将QScroller的配置拆分为独立接口。
    • 示例:定义IScrollBehavior接口,允许动态切换滚动策略。
cpp 复制代码
class IScrollBehavior {
public:
    virtual void applyScroll(QAbstractScrollArea *area) = 0;
};

class InertialScroll : public IScrollBehavior {
public:
    void applyScroll(QAbstractScrollArea *area) override {
        QScroller::grabGesture(area->viewport(), QScroller::TouchGesture);
        // ... 参数配置
    }
};

// 使用时注入行为
SmoothScrollArea area;
InertialScroll scrollBehavior;
scrollBehavior.applyScroll(&area);

5. 依赖倒置原则 (DIP)
  • 原则:依赖抽象而非具体实现。
  • 核心思想
    • 高层模块不应依赖低层模块,二者都应依赖抽象
    • 抽象不应依赖细节,细节应依赖抽象。
  • 通俗解释
    就像电脑的USB接口(抽象)------鼠标、键盘(细节)都依赖USB标准,而不是电脑直接依赖具体设备。
  • 应用
    • 高层模块(如主窗口)依赖IScrollBehavior接口,而非直接调用QScroller
cpp 复制代码
class MainWindow : public QMainWindow {
public:
    MainWindow(IScrollBehavior *scrollBehavior, QWidget *parent = nullptr) 
        : QMainWindow(parent), m_scrollBehavior(scrollBehavior) {
        QListWidget *list = new QListWidget(this);
        m_scrollBehavior->applyScroll(list); // 通过接口配置滚动
    }
private:
    IScrollBehavior *m_scrollBehavior;
};

// 依赖注入
InertialScroll inertialBehavior;
MainWindow window(&inertialBehavior);

最终代码结构(SOLID合规)

cpp 复制代码
// 1. 抽象接口(ISP + DIP)
class IScrollBehavior {
public:
    virtual void apply(QAbstractScrollArea *area) = 0;
};

// 2. 具体实现(SRP)
class InertialScroll : public IScrollBehavior {
public:
    void apply(QAbstractScrollArea *area) override {
        QScroller::grabGesture(area->viewport(), QScroller::TouchGesture);
        QScrollerProperties props;
        props.setScrollMetric(QScrollerProperties::DecelerationFactor, 0.2);
        QScroller::scroller(area->viewport())->setScrollerProperties(props);
    }
};

// 3. 可扩展的滚动区域(OCP + LSP)
class SmoothScrollArea : public QScrollArea {
public:
    explicit SmoothScrollArea(IScrollBehavior *behavior, QWidget *parent = nullptr) 
        : QScrollArea(parent) {
        behavior->apply(this);
    }
};

// 4. 高层模块依赖抽象(DIP)
int main() {
    InertialScroll inertialBehavior;
    SmoothScrollArea scrollArea(&inertialBehavior);
    
    QListWidget listWidget;
    SmoothScrollArea listScroll(&inertialBehavior);
    // ... 显示窗口
}

优势总结

  1. 可维护性:滚动逻辑与UI组件解耦,修改滚动行为无需改动控件代码。
  2. 可扩展性 :新增滚动策略(如弹簧效果)只需实现IScrollBehavior
  3. 可测试性:可通过Mock接口单独测试滚动行为。
  4. 灵活性:运行时动态切换滚动效果(如触屏/鼠标模式)。

通过严格遵循SOLID原则,Qt中的惯性滚动实现既满足了功能需求,又保持了代码的高内聚低耦合。

相关推荐
牛油果子哥q13 小时前
LLM 服务网关设计:流量分发、鉴权、限流、多模型路由、负载均衡、接口版本管理(C++ 网关落地)
运维·负载均衡
傲世仙尊13 小时前
从磁盘硬件到Ext文件系统-Linux磁盘级文件系统学习笔记
linux·运维·服务器·开发语言·c++
蓝速科技14 小时前
信创终端 POC 测试实战与选型避坑指南丨蓝速科技
运维·数据库·人工智能·科技·自然语言处理
曦夜日长14 小时前
Linux系统篇,进程概念(三):进程状态详解、僵尸进程与孤儿进程的深度解析、Slab机制的了解
linux·运维·服务器
liulilittle14 小时前
为什么采用全局管理缓存及状态:麻将客户端状态管理
服务器·网络·游戏·客户端·异步·mahjong·麻将
wdfk_prog14 小时前
VMware Ubuntu 虚拟机从 124 GB 压缩到 33 GB
运维·缓存·docker·容器
2601_9663771314 小时前
等保2.0最新标准新增安全数据处理要求后怎么办?等保一体机数据安全模块来助力
运维·网络·安全·等保一体机
2601_9639067814 小时前
桌面自动化工具|零代码录制自动化,无需联网本地离线用
运维·自动化
海宇AI14 小时前
零信任架构实战:基于海宇公安二要素认证即时版构建自动化灵活用工准入网关
运维·人工智能·架构·自动化
杨云龙UP14 小时前
MySQL Host is blocked because of many connection errors 导致 JDBC 连接失败排查与解决
linux·运维·网络·数据库·sql·mysql·登录失败