You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

共享对象工厂设计模式优化咨询及替代方案推荐

方案评估与优化建议

首先得说,你的现有方案已经精准实现了核心需求——让同ID的Widget共享Lease实例,而且用weak_ptr避免了内存泄漏,整体思路是站得住脚的。不过你提到的三个痛点确实有优化空间,咱们逐一拆解聊聊:

现有方案的优缺点

优点

  • 完美匹配业务逻辑:通过ID映射机制,确保同ID的Widget能复用同一个Lease
  • 内存安全:用weak_ptr跟踪实例生命周期,避免Lease被无用引用长期占用

缺点

  • 强耦合问题:Widget硬依赖Controller单例,不仅扩展受限,单元测试也很难做
  • 定时清理的低效与冗余:轮询式的定时任务不是最高效的资源管理方式,还导致CreateLease必须额外检查weak_ptr有效性,逻辑不够简洁

针对痛点的具体优化方案

1. 消除单例依赖:用依赖注入替代硬编码单例

单例最大的问题是把Widget和Controller死死绑定在一起。解决办法很简单:把Controller作为参数注入到Widget的构造函数里,而不是让Widget直接访问单例。

示例代码:

class Widget {
private:
    unsigned m_id{};
    std::shared_ptr<Lease> m_lease;
public:
    // 构造时传入Controller,摆脱单例依赖
    Widget(unsigned id, Controller& controller) 
        : m_id(id), m_lease(controller.CreateLease(id)) {}
};

这样Controller可以是全局对象、由上层容器管理,甚至测试时能传入Mock实现,灵活性提升一大截。

2. 事件驱动的过期条目移除:用shared_ptr自定义删除器替代定时任务

你头疼的定时清理问题,其实可以用shared_ptr的自定义删除器彻底解决。当最后一个持有Lease的shared_ptr被销毁时,删除器会自动触发,我们让它通知Controller从映射表中移除对应ID的条目——完全是事件驱动,没有时间窗口问题,也不需要轮询。

修改后的Controller实现(注意加上线程安全保护):

#include <mutex>
#include <map>
#include <memory>

class Lease {};

class Controller {
public:
    std::shared_ptr<Lease> CreateLease(unsigned id) {
        std::lock_guard<std::mutex> lock(m_mutex);

        auto it = m_leases.find(id);
        if (it != m_leases.end()) {
            // 这里的weak_ptr一定有效,因为实例销毁时条目已被移除
            return it->second.lock();
        }

        // 创建Lease并绑定自定义删除器
        auto raw_lease = new Lease();
        std::shared_ptr<Lease> shared_lease(raw_lease, [this, id](Lease* ptr) {
            delete ptr;
            // Lease销毁时自动从映射表中移除对应ID
            std::lock_guard<std::mutex> lock(m_mutex);
            m_leases.erase(id);
        });

        m_leases[id] = shared_lease;
        return shared_lease;
    }

private:
    std::mutex m_mutex; // 线程安全保护,多线程场景必须加
    std::map<unsigned, std::weak_ptr<Lease>> m_leases;
};

这个改动后,定时任务可以直接删掉——m_leases里永远只有有效的weak_ptr,不会存在过期条目。

3. 简化CreateLease逻辑:无需额外检查weak_ptr过期

因为用了自定义删除器,m_leases中的条目只会在Lease存活时存在。所以当CreateLease找到对应ID的条目时,weak_ptr一定能lock成功,直接返回即可,彻底去掉了冗余的有效性检查,逻辑瞬间简洁优雅。


推荐的设计模式:享元模式(Flyweight Pattern)

你的场景完全符合享元模式的定义:共享细粒度对象,通过工厂(这里的Controller)管理共享实例,根据唯一标识(ID)复用对象。享元模式的核心是分离内部状态(Lease本身的共享状态)和外部状态(Widget的私有状态),正好匹配你“同ID共享Lease”的需求。

优化后的方案就是享元模式的标准实现,结合C++智能指针特性,完美解决了生命周期管理的问题。


内容的提问来源于stack exchange,提问作者void.pointer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:00:43