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

带继承的Builder模式链式调用问题:寻求更优解决方案

链式Builder模式的类型匹配问题

我们有一个抽象构建类AbstractBufferBuilder,包含构建Buffer的通用方法:

class AbstractBufferBuilder {
public:
    AbstractBufferBuilder &setBufferData(...) {
        // 具体实现
        return *this;
    }
};

还有一个继承自它的具体构建类ConcreteBufferBuilder:

class ConcreteBufferBuilder : public AbstractBufferBuilder {
public:
    ConcreteBufferBuilder &addAttribute(...) {
        // 具体实现
        return *this;
    }

    Buffer* build(){
        return new Buffer(...);
    }
};

当尝试通过链式调用创建Buffer对象时:

ConcreteBufferBuilder().setBufferData(...).addAttribute(...).build();

这段代码无法编译——因为setBufferData()返回的是AbstractBufferBuilder类型引用,而该基类并没有addAttribute()方法。


已尝试的解决方案

1. CRTP模板基类方案

通过奇异递归模板模式(CRTP)让基类方法返回派生类的引用:

template<class Builder>
class AbstractBufferBuilder {
public:
    Builder &setBufferData(...) {
        // 具体实现
        return *dynamic_cast<Builder*>(this);
    }
};

class ConcreteBufferBuilder : public AbstractBufferBuilder<ConcreteBufferBuilder> {
public:
    ConcreteBufferBuilder &addAttribute(...) {
        // 具体实现
        return *this;
    }

    Buffer* build(){
        return new Buffer(...);
    }
};

该方案可以正常实现链式调用,但模板会增加编译和链接的开销,导致编译时间变长、生成的可执行文件体积增大。

2. 派生类包装函数方案

将基类的通用方法改为保护的实现函数,在派生类中编写同名的公开包装函数,返回派生类自身的引用:

class AbstractBufferBuilder {
protected:
    void setBufferDataImpl(...) {
        // 具体实现
    }
};

class ConcreteBufferBuilder : public AbstractBufferBuilder {
public:
    ConcreteBufferBuilder &setBufferData(...){
        AbstractBufferBuilder::setBufferDataImpl(...);
        return *this;
    }

    ConcreteBufferBuilder &addAttribute(...) {
        // 具体实现
        return *this;
    }

    Buffer* build(){
        return new Buffer(...);
    }
};

这种方式需要为每个新的Builder派生类重复编写包装代码,复用性差,维护成本高。


我希望保留链式调用的写法,请问有没有更优的解决方案?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 10:28:38