C++ 设计模式《统计辅助功能》

👨‍🎓 模式名称:访问者模式(Visitor)

👦 故事背景:

小明的系统上线后,业务越来越多。统计员小李的任务是每周统计:

  • 用户活跃数
  • 总订单收入
  • 好评评价数

但是这些业务对象(User, Order, Review)分属不同模块、由不同人维护,结构不同,统计逻辑也不同。

小李一开始采用了最直接的方法 ------ 在每个类里写统计逻辑:

❌ 没有使用访问者模式的代码(耦合高、不易扩展)

1. 各业务类都写了 analyze() 方法,分析逻辑分散在每个类中
csharp 复制代码
#include <iostream>
#include <vector>
#include <string>

class User {
public:
    std::string name;
    int loginDays;

    bool isActive() const {
        return loginDays > 30;
    }

    void analyze(int& activeUserCount) {
        if (isActive()) {
            activeUserCount++;
        }
    }
};

class Order {
public:
    int price;

    void analyze(int& totalRevenue) {
        totalRevenue += price;
    }
};

class Review {
public:
    int score;

    void analyze(int& positiveReviewCount) {
        if (score >= 4) {
            positiveReviewCount++;
        }
    }
};
2. 小李的分析函数 👇
csharp 复制代码
void doAnalysis(std::vector<User>& users, std::vector<Order>& orders, std::vector<Review>& reviews) {
    int activeUserCount = 0;
    int totalRevenue = 0;
    int positiveReviewCount = 0;

    for (auto& u : users) u.analyze(activeUserCount);
    for (auto& o : orders) o.analyze(totalRevenue);
    for (auto& r : reviews) r.analyze(positiveReviewCount);

    std::cout << "活跃用户数:" << activeUserCount << std::endl;
    std::cout << "总收入:" << totalRevenue << std::endl;
    std::cout << "好评数:" << positiveReviewCount << std::endl;
}

❌ 这会有什么问题?

问题点 描述
❌ 逻辑分散 每个类都负责"分析"自己的数据,导致功能散落四处
❌ 扩展困难 如果要加一个"导出为 Excel 的功能",又要修改每个类
❌ 违背开闭原则 每个新的分析需求都意味着要修改所有业务类
❌ 违反单一职责 原本只负责数据的业务类,现在还要处理"统计、导出"等行为

✅ 使用访问者模式:结构统一、处理分离

🧱 抽象访问者:数据分析器
csharp 复制代码
class Order;
class User;
class Review;

class AnalyticsVisitor {
public:
    virtual void visit(Order* order) = 0;
    virtual void visit(User* user) = 0;
    virtual void visit(Review* review) = 0;
    virtual ~AnalyticsVisitor() = default;
};
🧱 抽象业务对象(被访问者)
csharp 复制代码
class VisitableEntity {
public:
    virtual void accept(AnalyticsVisitor* visitor) = 0;
    virtual ~VisitableEntity() = default;
};
🧱 具体业务对象
csharp 复制代码
class Order : public VisitableEntity {
public:
    int price = 20;
    std::string category = "外卖";

    void accept(AnalyticsVisitor* visitor) override {
        visitor->visit(this);
    }
};

class User : public VisitableEntity {
public:
    std::string name = "张三";
    int loginDays = 45;

    void accept(AnalyticsVisitor* visitor) override {
        visitor->visit(this);
    }
};

class Review : public VisitableEntity {
public:
    int score = 4;
    std::string comment = "不错的服务";

    void accept(AnalyticsVisitor* visitor) override {
        visitor->visit(this);
    }
};
🧱 具体访问者:统计分析逻辑
csharp 复制代码
class DataAnalyzer : public AnalyticsVisitor {
public:
    int orderCount = 0;
    int totalRevenue = 0;
    int activeUsers = 0;
    int positiveReviews = 0;

    void visit(Order* order) override {
        orderCount++;
        totalRevenue += order->price;
    }

    void visit(User* user) override {
        if (user->loginDays > 30)
            activeUsers++;
    }

    void visit(Review* review) override {
        if (review->score >= 4)
            positiveReviews++;
    }

    void report() {
        std::cout << "订单数:" << orderCount << std::endl;
        std::cout << "总收入:" << totalRevenue << std::endl;
        std::cout << "活跃用户数:" << activeUsers << std::endl;
        std::cout << "好评数:" << positiveReviews << std::endl;
    }
};
🚀 使用示例
csharp 复制代码
int main() {
    std::vector<VisitableEntity*> system = {
        new Order(), new User(), new Review(),
        new Order(), new User(), new Review()
    };

    DataAnalyzer analyzer;

    for (auto entity : system) {
        entity->accept(&analyzer);
    }

    analyzer.report();

    for (auto e : system) delete e;
    return 0;
}

✅ 使用访问者模式的优势

优势 描述
👑 开闭原则 新增分析逻辑时,只加新的 Visitor 类,不动原有结构
🤝 统一接口 所有业务对象统一接受访问者
🧹 逻辑清晰 分析逻辑集中在访问者类中,业务对象职责单一
🛠️ 易扩展 可以创建多个访问者用于不同目的(如导出、展示)
相关推荐
缺点内向4 分钟前
如何在 C# 中将 Excel 工作表拆分为多个窗格
开发语言·c#·.net·excel
少废话h1 小时前
解决Flink中ApacheCommonsCLI版本冲突
开发语言·python·pycharm
天命码喽c1 小时前
GraphRAG-2.7.0整合Milvus-2.5.1
开发语言·python·milvus·graphrag
后端小张1 小时前
【JAVA进阶】Spring Boot 核心知识点之自动配置:原理与实战
java·开发语言·spring boot·后端·spring·spring cloud·自动配置
ZHE|张恒6 小时前
设计模式(十四)模板方法模式 — 定义流程骨架,把步骤差异留给子类
设计模式·模板方法模式
Mr_Xuhhh6 小时前
YAML相关
开发语言·python
阿巴~阿巴~6 小时前
JsonCpp:C++ JSON处理利器
linux·网络·c++·json·tcp·序列化和反序列化
咖啡の猫6 小时前
Python中的变量与数据类型
开发语言·python
前端达人6 小时前
你的App消息推送为什么石沉大海?看Service Worker源码我终于懂了
java·开发语言
汤姆yu7 小时前
基于springboot的电子政务服务管理系统
开发语言·python