有多少参数是一个合理的数字,大对象与原子参数。面向对象编程

发布于 2024-10-10 18:43:24 字数 188 浏览 0 评论 0原文

我是一名新开发人员,我想知道根据您的经验,构建类方法时更好的方法是什么,如果没有更好的方法,如何平衡您的决策:

  • 将一个大对象作为参数传递包含该方法所需的大部分变量。
  • 传递更多可能的原子个体变量,结果是生成具有大签名的方法。

对于即将发展的代码来说,什么更好?您认为合理的论点数量是多少?

i'm a novel developer and i would like to know in yours experience what is the better approach when your building class methods, and if there is not a better approach, how balance your decisions with respect to:

  • Pass as arguments a big object that contains most of the variables needed for the method.
  • Pass the more atomic individuals variables possibles, with the consequences of generate methods with big signatures.

What is better for a code that is going to evolve? and what do you think is a reasonable number of arguments?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

少女情怀诗 2024-10-17 18:43:24

如果参数集合中的共性允许的话,我强烈主张传递一个对象。

为什么?

因为 X% 的精力花在维护现有代码上,并且添加新参数比向对象添加属性要困难得多,尤其是在相互链式调用并传递这些新参数的方法中。

请注意,从具有方法的意义上来说,这本身不一定是一个类。只是一个存储容器(要么是异构映射/字典,要么是为了类型安全,是支持它的 C 类型语言中的结构)。

示例(我将使用伪代码,随意它基于哪种语言):


首先,让我们使用参数列表查看旧代码和新代码

旧代码:

function f1(arg1, arg2, arg3, arg4, arg5) {
    res = f2(arg1, arg2, arg3, arg4);
}
function f2(arg1, arg2, arg3, arg4) {
    res = f3(arg1, arg2, arg4);
}
function f3(arg1, arg2, arg4) {
    res = f4(arg1, arg4);
}
function f4(arg1, arg4) {
    return arg1 + arg4;
}

新代码(需要在 f4() 中添加 arg6):

function f1(arg1, arg2, arg3, arg4, arg5, arg6) {       // changed line
    res = f2(arg1, arg2, arg3, arg4, arg6);             // changed line
}
function f2(arg1, arg2, arg3, arg4, arg6) {             // changed line
    res = f3(arg1, arg2, arg4, arg6);                   // changed line
}
function f3(arg1, arg2, arg4, arg6) {                   // changed line
    res = f4(arg1, arg4, arg6);                         // changed line
}
function f4(arg1, arg4, arg6) {                         // changed line
    return arg1 + arg4 + arg6;                          // changed line
}

正如你可以的看,对于 4 级嵌套调用,我们更改了所有 4 个函数,每个函数至少有 2 行。哎呀。因此,对于 10 级嵌套调用,添加 1 个参数会更改所有 10 个函数和 20 行。


现在,有一个相同更改的示例,除了 arg 列表现在是一个对象(或者,对于动态语言,异构映射即可:)

class args_class {
    public: 
        int arg1, arg2, arg3, arg4, arg5;
    }
}
args_class arg_object;

function f1(arg_object) {       
    res = f2(arg_object);             
}
function f2(arg_object) {       
    res = f3(arg_object);                   
}
function f3(arg_object) {                   
    res = f4(arg_object);                         
}
function f4(arg_object) {                         
    return arg_object.arg1 + arg_object.arg4;                          
}

我们需要更改什么来添加 arg6?

class args_class {
    public: 
        int arg1, arg2, arg3, arg4, arg5, arg6;                 // line changed
    }
}
// f1..f3 are unchanged
function f4(arg_object) {                         
    return arg_object.arg1 + arg_object.arg4 + arg_object.arg6; // line changed
}

就是这样。对于 4 级嵌套方法或 10 级嵌套方法,您只需要更改 2 行。

哪一个维护工作量较少?

I would argue strongly in favor of passing around an object, if the commonality in the sets pf arguments allows it.

Why?

Because X% of effort goes to maintain existing code and it's a LOT harder to add new parameters - especially in methods that chain-call each other and pass those new parameters - than to add a property to an object.

Please note that this doesn't have to be a CLASS per se, in a sense of having methods. Merely a storage container (either a heterogeneous map/dictionary, or for type safety, a struct in C-type langages that support it).

Example (I'll use pseudocode, feel free which language(s) it's based on):


First, let's see old and new code using argument lists

Old code:

function f1(arg1, arg2, arg3, arg4, arg5) {
    res = f2(arg1, arg2, arg3, arg4);
}
function f2(arg1, arg2, arg3, arg4) {
    res = f3(arg1, arg2, arg4);
}
function f3(arg1, arg2, arg4) {
    res = f4(arg1, arg4);
}
function f4(arg1, arg4) {
    return arg1 + arg4;
}

New code (need to add arg6 in f4()):

function f1(arg1, arg2, arg3, arg4, arg5, arg6) {       // changed line
    res = f2(arg1, arg2, arg3, arg4, arg6);             // changed line
}
function f2(arg1, arg2, arg3, arg4, arg6) {             // changed line
    res = f3(arg1, arg2, arg4, arg6);                   // changed line
}
function f3(arg1, arg2, arg4, arg6) {                   // changed line
    res = f4(arg1, arg4, arg6);                         // changed line
}
function f4(arg1, arg4, arg6) {                         // changed line
    return arg1 + arg4 + arg6;                          // changed line
}

As you can see, for 4-level nested calls, we changed ALL 4 functions, at the volume of at least 2 lines per function. YIKES. So for 10-level nested calls, adding 1 parameter changes all TEN functions and 20 lines.


Now, an example of the same change, except the arg list is now an object (or, for dynamic languages, a heterogeneous map would do :)

class args_class {
    public: 
        int arg1, arg2, arg3, arg4, arg5;
    }
}
args_class arg_object;

function f1(arg_object) {       
    res = f2(arg_object);             
}
function f2(arg_object) {       
    res = f3(arg_object);                   
}
function f3(arg_object) {                   
    res = f4(arg_object);                         
}
function f4(arg_object) {                         
    return arg_object.arg1 + arg_object.arg4;                          
}

And what do we change to add arg6?

class args_class {
    public: 
        int arg1, arg2, arg3, arg4, arg5, arg6;                 // line changed
    }
}
// f1..f3 are unchanged
function f4(arg_object) {                         
    return arg_object.arg1 + arg_object.arg4 + arg_object.arg6; // line changed
}

That's it. For 4-level nested methods, or for 10-level nested methods, you ONLY change 2 lines both.

Which one is less work to maintain?

折戟 2024-10-17 18:43:24

我认为这完全取决于函数参数本身的上下文。如果您依赖于某事的元素,那么我会将该某事的引用作为参数传递(无论它是指向以下接口的引用/指针)该对象或对象定义本身的引用/指针是实现细节)。

如果参数不是直接从对象派生的,并且参数数量很少(也许五个或更少?取决于你),那么我会传递原子参数。

如果可能存在大量参数,那么我将创建某种 init 结构作为参数,其中调用代码实例化并填充该结构,然后将对其的引用作为参数传递。

I think it all depends on the context of the function parameters themselves. If you're relying on elements of some thing, then I'd pass a reference of that some thing as a parameter (whether it's a reference/pointer to an interface of that object or a reference/pointer to the object definition itself is an implementation detail).

If the parameter isn't derived directly from an object and there are a small number of parameters (five or less maybe? up to you really), then I'd pass atomic arguments.

If there are potentially a large number of arguments, then I'd create some sort of an init struct as a parameter, where the calling code instantiates and fills the struct and then passes a reference to it as an argument.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文