避免向下转型,双重分派。

3

我做了类似以下代码的事情:

void launchPipeline(IQueryFactory & queryFactory, IQuerySender &querySender, IValidateResponse &responseValidator)
{
    std::unique_ptr<IQuery> query = queryFactory.getInstance();

    /*
    auto a,b,c = querySender.send(query);
    //we just get a lot of params from that function
    */

    if(responseValidator.validate(query, a, b, c)
    {
        //do something
    }
}
class IValidateResponse
{
   public:
    virtual bool validate(IQuery & query, int a, int b, int c) = 0;
};

class QueryAValidator
{
   public:
    bool validate(IQuery & query, int a, int b, int c) override
    {
        const auto & queryA = dynamic_cast<const QueryA &>(query);
        //do something
    }
};

这段代码很完美,因为匹配了IQueryFactoryIValidateResponse的相应类型。但我在想是否有一些花哨的方法可以避免这种情况?

我正在考虑使用QueryVisitor,但我不确定如何实现它,访问函数需要采用a、b、c等参数,这看起来在IQuery接口上会很奇怪,例如 query.accept(visitor, a, b, c)

或者我可以将这些参数存储在访问器中,但这仍然感觉不太顺畅,特别是当编写测试时。目前我有所谓的“验证器测试”,其中我只需放置一个假响应并测试具体的验证器类,将访问器添加到其中会使它们变得更加复杂。

你会如何解决这个问题呢?


只是好奇,但 validate 不是声明为公共的,它是私有的。launchPipeline 如何调用此方法? - selbie
我的错,疏忽了。 - konradk
这只是用于单元测试代码吗?如果只是用于测试代码,那又有谁在乎呢?在测试代码中允许存在一定程度的不完美,这样你就不必重新设计所有产品代码的对象模型以避免强制转换。 - selbie
1个回答

0
在IQuery中定义一个纯虚函数并调用它foo(int a, int b, int c)。在QueryA中,您可以使用动态转换后定义的代码"//do something"来重写foo。将动态转换替换为query.foo(a, b, c)。

事实是我想要一个专门的接口来处理这个,即IValidateResponse。 - konradk
1
在IQuery中定义一个纯虚函数呢?如 virtual IValidateResponse* getValidateResponse() = 0; 通过该函数,每个查询都可以返回自己的 ValidateResponse。 - eberhard
我刚看到你在问题上打了unit-test的标签。所以,在测试中不要使用QueryFactory,而是用单独的代码测试每个具体类型的IQuery。这意味着,在测试中不要使用IQuery,而是使用QueryA。 - eberhard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接