选择构造函数的更好模式

时间:2016-11-18 23:18:39

标签: c++ design-patterns constructor

我有类Foo,它有多个构造函数。

class Foo
{
public:
Foo( Param1, Param2 );
Foo( Param1, Param3, Param4 );
Foo( Param1, Param4 );
Foo( Param1, Param2, Param4 );
}

构造函数的实际参数列表很大,我不想直接从其他项目提供对这些构造函数的访问(否则我需要导出这4个构造函数)。我知道避免这种多重构造函数的最佳模式是 Builder Pattern 。但这会给这个类的客户造成混淆,关于哪个param是可选的,哪个param不是。另外每个构造函数都基于参数进行某些验证。因此,在实际使用此对象的任何方法之前,我需要通用的地方进行此类验证。

目前我们正在计划的内容如下:

  1. 无变化Foo类。

  2. 定义FooParam结构

    struct FooParam
    {
        Param1 p1;
        Param2 p2;
        Param3 p3;
        Param4 p4;
    }
    
  3. 厂:

    Foo* CreateFoo( FooParams& foo )
    {
        if( foo.Param2 )
        {
            if( foo.Param4 )
            {
                return new Foo( foo.param1, foo.param2, foo.param4);
            }
            else
                return  new Foo( foo.param1, foo.param2);
        }
        else if( foo.param4 )
        {
            if(foo.param3)
                return new Foo( foo.param1, foo.param3, foo.param4 );
            else
                return new Foo( foo.param1, foo.param4 );
        }
    
        throw new Exception("Invalid Parameter" );
    }
    
  4. 我认为我们可以在第3步做得更好。但现在确定如何?

2 个答案:

答案 0 :(得分:1)

如果由于某些原因不想公开构造函数,可以根据模板和完美转发在工厂方法后面隐藏它们:

class Foo {
    // defined somewhere
    Foo( Param1, Param2 );
    Foo( Param1, Param3, Param4 );
    Foo( Param1, Param4 );
    Foo( Param1, Param2, Param4 );

private:
    template<typename... Args>
    static auto factory(Args&&... args) {
        Foo foo{std::forward<Args>(args)...};
        // do whatever you want here
        return foo;
    }
}

无需在运行时抛出任何东西 如果不存在接受这些参数的构造函数,则会收到编译时错误。

否则,另一种惯用方法是使用named constructors 我直接复制并粘贴上面链接中的示例:

class Game {
public:
    static Game createSinglePlayerGame() { return Game(0); }
    static Game createMultiPlayerGame() { return Game(1); }

protected:
    Game (int game_type);
};

不确定这是否符合您的要求。

那就是说,想想这样做有什么好处:

CreateFoo({ Param1V, Param3V });

更糟糕的是,这个:

FooParams params{ Param1V, Param3V };
CreateFoo(params);

而不是:

new Foo{Param1V, Param3V};

通过引入中级课程,您实际上并没有帮助您班级的用户 他们仍然需要记住特定情况下所需的参数。

答案 1 :(得分:-1)

作为用户,我更喜欢

Foo* CreateFoo(Param1* P1, Param2* P2, Param3* P3, Param4* P4);

为什么我要构建一个struct来传递一些(可能是NULL)参数?