C++ 设计模式 《爬虫围城危机:小明用代理模式自救》

👨‍🎓 模式名称:代理模式(Proxy Pattern)

🧵 故事背景

小明的“校园万能生活平台”App上线后,大受欢迎!

然而没几天,他发现服务器响应变慢,数据库压力暴涨。查日志发现——

👾 有一群爬虫在疯狂请求接口!

GET /api/user_info?id=12345
GET /api/class_schedule
GET /api/favoritelist
...

小明都快疯了 😵‍💫!

于是,他请来了“小明安全屋团队”,做了两件事:

  1. 所有App API请求,都必须经过代理访问后端服务
  2. 在代理中加入身份验证、访问计数、缓存机制等功能

于是,“代理模式”就派上用场了!

🏗 没有代理模式(❌ 不加控制,裸奔服务器)

class RealServerAPI {
public:
    void getUserInfo(const std::string& userId) {
        std::cout << "📡 获取用户信息:" << userId << std::endl;
    }
};

客户端直接调用:

RealServerAPI api;
api.getUserInfo("xiaoming123");

🔥 没有身份校验、没有日志、不能限速,爬虫来了你就完蛋!

不使用代理模式做限制的完整代码

#include <iostream>
#include <string>

#include <unordered_map>
#include <unordered_set>

class UserService {
public:
    std::string getUserInfo(const std::string& userId) {
        // 权限校验
        if (blacklist.find(userId) != blacklist.end()) {
            return "⛔ 你被禁止访问";
        }

        // 访问计数
        accessCount[userId]++;
        std::cout << "👀 用户 " << userId << " 已访问 " << accessCount[userId] << " 次\n";

        // 缓存逻辑
        if (cache.find(userId) != cache.end()) {
            std::cout << "📦 从缓存中返回用户信息\n";
            return cache[userId];
        }

        // 模拟数据库查询
        std::string info = "📡 用户信息:" + userId;
        cache[userId] = info;
        return info;
    }

private:
    std::unordered_set<std::string> blacklist = { "hacker" };
    std::unordered_map<std::string, int> accessCount;
    std::unordered_map<std::string, std::string> cache;
};

int main() {
    UserService* realService = new UserService();

    // 客户端只面对 protectedService
    std::cout << realService->getUserInfo("xiaoming") << "\n\n";
    std::cout << realService->getUserInfo("xiaoming") << "\n\n";
	std::cout << realService->getUserInfo("hacker") << "\n\n";
    delete realService;
}

在这里插入图片描述

这里虽然做了限制,但是有如下缺点
😵‍💫 缺点:

  • 职责太多:业务类同时负责权限校验、计数、缓存、数据处理,难以维护。
  • 重复性强:每个接口都要复制这套逻辑。
  • 可测试性差:单测很困难,因为功能耦合严重。
  • 另外,有的时候类可能是第三方封闭库的一部分。这样我们就没办法做到上面的限制操作,因为我们没办法改别人的类

✅ 使用代理模式:增加身份验证 + 访问计数+ 缓存机制

1️⃣ 接口抽象:
class IUserService {
public:
    virtual std::string getUserInfo(const std::string& userId) = 0;
    virtual ~IUserService() = default;
};
2️⃣ 真实服务类:
class RealUserService : public IUserService {
public:
    std::string getUserInfo(const std::string& userId) override {
        return "📡 用户信息:" + userId;
    }
};
3️⃣ 权限代理:
class PermissionProxy : public IUserService {
public:
    PermissionProxy(IUserService* service) : service(service) {}

    std::string getUserInfo(const std::string& userId) override {
        if (blacklist.find(userId) != blacklist.end()) {
            return "⛔ 你被禁止访问";
        }
        return service->getUserInfo(userId);
    }

private:
    IUserService* service;
    std::unordered_set<std::string> blacklist = { "hacker" };
};
4️⃣ 计数代理:
class AccessCounterProxy : public IUserService {
public:
    AccessCounterProxy(IUserService* service) : service(service) {}

    std::string getUserInfo(const std::string& userId) override {
        accessCount[userId]++;
        std::cout << "👀 用户 " << userId << " 已访问 " << accessCount[userId] << " 次\n";
        return service->getUserInfo(userId);
    }

private:
    IUserService* service;
    std::unordered_map<std::string, int> accessCount;
};
5️⃣ 缓存代理:
class CacheProxy : public IUserService {
public:
    CacheProxy(IUserService* service) : service(service) {}

    std::string getUserInfo(const std::string& userId) override {
        if (cache.find(userId) != cache.end()) {
            std::cout << "📦 从缓存中返回\n";
            return cache[userId];
        }
        std::string info = service->getUserInfo(userId);
        cache[userId] = info;
        return info;
    }

private:
    IUserService* service;
    std::unordered_map<std::string, std::string> cache;
};
🏗 最终组装(链式代理):
int main() {
    IUserService* realService = new RealUserService();

    IUserService* cached = new CacheProxy(realService);
    IUserService* counted = new AccessCounterProxy(cached);
    IUserService* protectedService = new PermissionProxy(counted);

    // 客户端只面对 protectedService
    std::cout << protectedService->getUserInfo("xiaoming") << "\n\n";
    std::cout << protectedService->getUserInfo("xiaoming") << "\n\n";
    std::cout << protectedService->getUserInfo("hacker") << "\n";

    delete protectedService;
    delete counted;
    delete cached;
    delete realService;
}
完整代码
#include <iostream>
#include <string>

#include <unordered_map>
#include <unordered_set>

class IUserService {
public:
    virtual std::string getUserInfo(const std::string& userId) = 0;
    virtual ~IUserService() = default;
};

class RealUserService : public IUserService {
public:
    std::string getUserInfo(const std::string& userId) override {
        return "📡 用户信息:" + userId;
    }
};

class PermissionProxy : public IUserService {
public:
    PermissionProxy(IUserService* service) : service(service) {}

    std::string getUserInfo(const std::string& userId) override {
        if (blacklist.find(userId) != blacklist.end()) {
            return "⛔ 你被禁止访问";
        }
        return service->getUserInfo(userId);
    }

private:
    IUserService* service;
    std::unordered_set<std::string> blacklist = { "hacker" };
};

class AccessCounterProxy : public IUserService {
public:
    AccessCounterProxy(IUserService* service) : service(service) {}

    std::string getUserInfo(const std::string& userId) override {
        accessCount[userId]++;
        std::cout << "👀 用户 " << userId << " 已访问 " << accessCount[userId] << " 次\n";
        return service->getUserInfo(userId);
    }

private:
    IUserService* service;
    std::unordered_map<std::string, int> accessCount;
};

class CacheProxy : public IUserService {
public:
    CacheProxy(IUserService* service) : service(service) {}

    std::string getUserInfo(const std::string& userId) override {
        if (cache.find(userId) != cache.end()) {
            std::cout << "📦 从缓存中返回\n";
            return cache[userId];
        }
        std::string info = service->getUserInfo(userId);
        cache[userId] = info;
        return info;
    }

private:
    IUserService* service;
    std::unordered_map<std::string, std::string> cache;
};

int main() {
    IUserService* realService = new RealUserService();

    IUserService* cached = new CacheProxy(realService);
    IUserService* counted = new AccessCounterProxy(cached);
    IUserService* protectedService = new PermissionProxy(counted);

    // 客户端只面对 protectedService
    std::cout << protectedService->getUserInfo("xiaoming") << "\n\n";
    std::cout << protectedService->getUserInfo("xiaoming") << "\n\n";
    std::cout << protectedService->getUserInfo("hacker") << "\n";

    delete protectedService;
    delete counted;
    delete cached;
    delete realService;
}

在这里插入图片描述

✅ 优势总结

比较维度硬编码处理代理模式处理
结构清晰❌ 混乱✅ 职责分明
易于扩展❌ 修改原类代码✅ 添加新代理类即可
测试性好❌ 很难隔离测试✅ 每个代理功能可独立测试
灵活组装❌ 所有逻辑耦合✅ 可按需组合代理链
避免重复代码❌ 每个接口都要写一遍✅ 写一次代理,可全局复用
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值