質問

In the book Clean Code, Robert C. Martin says that we should avoid polyadic functions (functions that contain four or more arguments).

One of the solutions presented by him is the use of objects as parameters.

In some cases it is easy to identify arguments that can become or be grouped into an object. However, in other cases, this is not a simple task.

For example: Parameters being passed to a method in a DAO (Data Access Object) class, which will be used in an SQL script. They will only be used in that single location throughout the code. There is no other point in the code that will make use of these parameters.

I am currently considering these objects as a DTO (Data Transfer Object), but I have a feeling that this would not be the best classification for these objects.

I have this feeling, because in languages ​​like C# and Java, where basically each file is a class. Having a file with a DTO class, which will be passed as a method parameter, in a single location in the code, that sounds weird to me.

Is it correct to classify these objects as DTO? Or is there another more suitable nomenclature?

Is there any other solution for these cases of functions with parameters that will only be used in that function (to avoid having to keep creating files/classes that only serve to be passed as parameters)? Perhaps the use of dictionaries (key and value), would be feasible (Even if you lose all the autocomplete help from IDEs)?

役に立ちましたか?

解決

In my opinion such rules should be treated as a recommendation and not a inflexible rule. If parameters have a good reason to be grouped they should be put into a class regardless of how many there are. I would not think grouping parameters just to avoid the 4-parameter limit is sufficient justification.

Examples

// Wrap parameter to make the unit unambiguous
Foo(Angle.FromDegree(45)); 

// This would not improve readability in my opinion
Bar( new BarParameters(1, 2, 3), new BarParameters2(4, 5, 6)); 

Another example could be the DrawRectangle methods. One overload just takes a pen and a rectangle: DrawRectangle(Pen, Rectangle). But there is also an overload that takes individual parameters DrawRectangle(Pen, Int32, Int32, Int32, Int32). I find that this works just fine, the pattern of x, y, width, height is sufficiently common that it should be fairly quickly recognized even by junior developers.

If you should call parameter objects for 'DTO' or not should depend your naming conventions. There is as far as I know no generally accepted naming convention for 'DTO', so the most important thing would be to be consistent in your own projects. I personally only use 'DTO'-label for types that need serializing, but that is just my own convention.

他のヒント

It's not a weird thing to have a class that is used only in one place to reduce a long parameter list, anymore than it's a bad thing to have a method that's called only once to cut down a lengthy caller method.

In both cases the point is to make the code more readable and self-explanatory than it would be if humans had to read through long argument lists or scroll through long method listings. Never judge your code base by thinking "But this is unnecessary, the computer could process it just as well as it is!" The point of good software engineering is to transform code into a form where it's equally well processable by computer, but better by human.

Well, replacing group of parameters with one specific object, which will be used only once just to reduce the number of parameters is not the best approach either. The point of having not more than 3-4 is not only about having better readable code, but more about having cleaner architecture. You can pass objects to your method, but objects should be meaningful and possibly could be reused somewhere else.

For example:

findUsers(name, email, phone) can be replaced with findUsers(contactDetails), contactDetails can be reused anywhere, even in the User class.

The point is to break down big things in smaller ones, so smaller pieces can be reused everywhere and they are less coupled with each other. Maybe your group of params can be replaced with 2 meaningful objects, which make sense and can be reused. Polyadic function is a flag which tells you that something is not perferct in your architecture, something is too big and doing too much. There is no universal solutions, pretty much depends on your particular case, so it's better to discuss having some real code.

ライセンス: CC-BY-SA帰属
所属していません softwareengineering.stackexchange
scroll top