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

关于Null Object模式下Getter两种实现方式的技术疑问

关于Null Object模式中Getter实现的两种方案分析

嘿,这个问题戳中了Null Object模式里很容易忽略的细节——毕竟虽然我们都知道要尽量避免Getter,但真遇到必须用的场景,返回值的处理确实得仔细权衡。咱们来拆解你提到的第一种实现,再聊聊另一种更常见的优化方案,以及各自的优劣。

第一种实现:按值返回空容器

你给出的代码大致是这样的(我补全了细节让逻辑更完整):

// 假设SomeObject是已定义的业务类型
class NullObject {
public:
    std::vector<SomeObject> get() { return {}; }
};

class SomeImplementation {
private:
    std::vector<SomeObject> someVectorMember;
public:
    std::vector<SomeObject> get() { return someVectorMember; }
};

// 调用方式
const std::vector<SomeObject>& object = instance.get();

核心细节:临时对象的生命周期

这里有个关键的C++规则:当你把临时对象绑定到const左值引用上时,这个临时对象的生命周期会被延长到引用的生命周期结束。所以你的调用方式是安全的,不会出现悬空引用的问题。

但这种方式有个明显的缺点:每次调用NullObject::get()都会创建一个新的临时空vector。虽然空vector的构造、析构开销极小(大多数实现里空vector只存几个指针,没有堆内存分配),但如果是高频调用的场景,累积起来的开销还是能感知到的。另外,SomeImplementation::get()按值返回成员的话,若容器里存了大量元素,拷贝开销会非常大,这显然不是最优选择。


第二种实现:返回静态空容器的const引用

这是更常用的优化方案,把Null Object的返回值改成静态常量的引用,同时让真实实现也返回成员的const引用,保持接口完全一致:

class NullObject {
public:
    const std::vector<SomeObject>& get() {
        // 静态局部变量,程序生命周期内仅初始化一次
        static const std::vector<SomeObject> emptyVector{};
        return emptyVector;
    }
};

class SomeImplementation {
private:
    std::vector<SomeObject> someVectorMember;
public:
    const std::vector<SomeObject>& get() const {  // 加const保证成员不被意外修改
        return someVectorMember;
    }
};

// 调用方式不变
const std::vector<SomeObject>& object = instance.get();

优势

  1. 性能最优:静态空容器只会被初始化一次,后续调用都直接返回它的引用,没有临时对象的构造/拷贝开销;真实实现返回成员的引用,也避免了大容器的拷贝。
  2. 接口一致性:两种实现的get()返回类型完全一致,调用方不需要区分当前实例是Null Object还是真实实现,完美符合Null Object模式“透明处理空对象”的设计初衷。

需要注意的坑

  • 必须返回const引用:如果返回非const引用,有人不小心修改了这个静态空容器,所有使用Null Object的地方都会受到影响,完全违背了Null Object的语义。
  • 静态变量的线程安全:C11及以后的标准保证,静态局部变量的初始化是线程安全的(多线程第一次调用时不会出现竞态条件),但如果项目还在使用老版本编译器(比如C03及之前),需要自行加锁保证线程安全。

两种方案的选择建议

  • 如果get()调用频率不高,或者容器本身很小,第一种按值返回的方案足够简单,不需要考虑静态变量的初始化问题,代码可读性也更好。
  • 如果是高频调用场景,或者容器可能很大,第二种返回const引用的方案显然更合适,能有效避免不必要的性能开销。
  • 无论选哪种,一定要保证两个类的get()接口完全一致——要么都返回const引用,要么都按值返回,这样调用方才能无缝处理Null Object和真实实现,不用额外做判断。

内容的提问来源于stack exchange,提问作者Newbie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:36:30