Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 减少构造函数的参数数量_Oop_Design Patterns_Language Agnostic - Fatal编程技术网

Oop 减少构造函数的参数数量

Oop 减少构造函数的参数数量,oop,design-patterns,language-agnostic,Oop,Design Patterns,Language Agnostic,我正在阅读“干净的代码”,并且很难理解如何将我的一些函数(通常是构造函数)保持在最多3个参数 通常,我的对象需要大量的信息才能工作——我是否应该制作一个小构造函数,然后使用mutator函数为它们提供所有信息?这似乎并不比仅仅使用一个大的构造函数更好 例如,我有一个“MovablePatch”类。它允许用户在窗口中拖动一个正方形。它需要几个参数,包括半径、颜色、渲染器、初始位置和可见性。目前,我从GUI收集所有这些信息,然后调用: MovablePatch(int radius, Rendere

我正在阅读“干净的代码”,并且很难理解如何将我的一些函数(通常是构造函数)保持在最多3个参数

通常,我的对象需要大量的信息才能工作——我是否应该制作一个小构造函数,然后使用mutator函数为它们提供所有信息?这似乎并不比仅仅使用一个大的构造函数更好

例如,我有一个“MovablePatch”类。它允许用户在窗口中拖动一个正方形。它需要几个参数,包括半径、颜色、渲染器、初始位置和可见性。目前,我从GUI收集所有这些信息,然后调用:

MovablePatch(int radius, Renderer* renderer, Color color,  Position initial, bool visibility)

这些只是我在这门课上需要的一些东西。有人能建议我如何打包这些信息以传递给构造函数吗?我在这里没有看到任何明显的“将其划分为更小的类”出现。

您正在传递的一些内容可以抽象为更大的结构。例如,将
可见性
颜色
半径
放置到您定义的对象中可能有意义。然后,这个类的一个实例,称为
ColoredCircle
,可以被传递到
MovablePatch
的构造函数中。彩色圆圈不在乎它在哪里,也不在乎它使用的是什么渲染器,但MovablePatch会在意

我的主要观点是,从面向对象的角度来看,
radius
实际上不是一个整数,而是一个半径。您希望避免这些冗长的构造函数列表,因为理解这些内容的上下文是令人生畏的。如果您将它们收集到一个更大的类中,就像您使用
Color
Position
已有的那样,您可以传递更少的参数,使其更易于理解。

您可以

MovablePatch(Renderer* renderer, CircleAppearance circleAppearance)
CircleAppearance收集其他信息的地方

然而,clean code和其他概括了好代码应该是什么样子的书的目标是80%的代码。您的代码似乎比典型的LoB(业务线)品种“更接近金属”。因此,您可能会遇到某些编码理想不适用的地方


最重要的一点是,你正在考虑这个问题,并努力保持事物的整洁

一个好的选择是使用构建器模式,其中每个“setter”方法返回自己的实例,您可以根据需要链接这些方法

在您的情况下,您将获得一个新的MovablePatchBuilder

这种方法非常有用,您可以在许多不同的框架和语言中找到它

请参阅一些示例。

此处的示例非常有用。在你的情况下,你可能会

class PatchBuilder
{
public:
    PatchBuilder() { }
    PatchBuilder& radius(int r) { _radius = r; return *this; }
    PatchBuilder& renderer(Renderer* r) { _renderer = r; return *this; }
    PatchBuilder& color(const Color& c) { _color = c; return *this; }
    PatchBuilder& initial(const Position& p) { _position = p; return *this; }
    PatchBuilder& visibility(bool v) { _visibility = v; return *this; }

private:
    friend class MovablePatch;
    int _radius;
    Renderer* _renderer;
    Color _color;
    Position _position;
    bool _visibility;
};

class MovablePatch
{
public:
    MovablePatch( const PatchBuilder& b ) :
        _radius( b._radius );
        _renderer( b._renderer );
        _color( b._color );
        _position( b._position );
        _visibility( b._visibility );
    {

    }

private:
    int _radius;
    Renderer* _renderer;
    Color _color;
    Position _position;
    bool _visibility;
};
那你就这样用吧

int
main()
{
    MovablePatch foo = PatchBuilder().
        radius( 1.3 ).
        renderer( asdf ).
        color( asdf ).
        position( asdf ).
        visibility( true )
     ;
}
过于简化了,但我认为这一点已经被理解了。如果需要某些参数,可以将其包含在
PatchBuilder
构造函数中:

class PatchBuilder
{
public:
    PatchBuilder(const Foo& required) : _foo(required) { }
    ...
};
显然,如果所有参数都是必需的,那么这种模式就会退化为原始问题,在这种情况下,命名参数习惯用法就不适用了。关键是,这不是一个一刀切的解决方案,正如Adam在下面的评论中所描述的那样,这样做会带来额外的成本和一些开销。

不要从表面上接受“你的构造函数中的参数不得超过3个”这样的格言。如果你有一点点机会使一个对象不可变,就让它不可变;如果它是不可变的,意味着它将有一个具有50个参数的构造函数,那么就这样吧;去争取吧不要再想了

即使对象是可变的,您仍然应该传递尽可能多的参数给它的构造函数,以便在构造之后它立即处于有效和有意义的状态。在我的书中,绝对不允许在调用任何其他方法之前,在segfault的惩罚下知道必须调用哪些神奇的mutator方法(有时甚至是以正确的顺序)


话虽如此,如果您真的想减少构造函数或任何函数的参数数量,只需向该方法传递一个接口,它可以调用该接口,从中获取工作所需的内容。

查看生成器模式。您必须遵循该指导原则吗?否则,我会说忽略它,因为它不知道如何应用它。在我看来,如果按照指南进行的修改不是直观的,那么通常不值得重构代码以确保无论发生什么情况都遵循指南。对于容易导致更复杂(因此容易出现错误)代码甚至没有更好可读性的非直觉解决方案(例如前面提到的小构造函数,后面跟着mutator函数调用或builder模式,这两种方法都很容易忘记设置某个值)在我出生之前,我就已经用一个简单的
struct
将相关属性作为一个参数来传递了。我很确定。这不只是转移了问题吗?您还必须以某种方式初始化
ColoredCircle
类,并且仍然剩下四个参数…@MartinStettner,是的,您必须首先初始化
ColoredCircle
,但这应该是四个参数。这意味着
MovablePatch
将只接受一个
ColoredCircle
和一个
Renderer*
Position
应该存储在补丁中还是存储在圆中?我认为补丁有位置,而不是圆。这至少将渲染器与圆的特征分开。那很好。如果需要,您可以稍后组织圆属性。还请记住,通过将
ColoredCircle
作为一个单独的结构,它可以有自己的构造函数来提供默认值,因此,如果程序员实际上不想指定他们不必指定的所有内容,那么它就会在ctor上变得一团糟