'How to design a utility class?
But I don't know if I should go for static methods, just a header, a class, or something else?
What would be best practice? But, I don't want to have an instance of a utility class.
I want to add functions like:
Uint32 MapRGB (int r, int g, int b);
const char* CopyString(const char* char);
// etc. You know: utility methods...
Solution 1:[1]
Don't put them in a class; just make them non-member functions at namespace scope.
There's no rule that says every function has to be a member function of some class.
Solution 2:[2]
One factor is whether to even put them in a class, or just put them as nomembers in a namespace (in Java, you'd have to use a class, but C++ offers namespaces).
If you do make it a class member, then the most important decision you have to make about each function is whether it would require or should affect any state that is not received or passed via a its parameters and return value. If it does not, then it should be made static
, since you will not use the "this" hidden argument.
One argument for using a class instead of a namespace is if your utility class may need to invoke additional methods for its implementation (e.g., in a case of recursion, complex calculations, etc.). You could then make your method static public
, and anything it is implemented over static private
. It's been many years since I used C++, but I don't think you can "hide" non-member functions in a namespace (someone correct me if I'm wrong).
In terms of designing the function interface, consider the number of arguments. If there are too many incoming arguments (especially if they are of similar types and some are related), you may want to consider using additional types instead of passing multiple args. For example, instead of calculateVolume(int x, int y, int z)
, you may want to do something like calculateVolume(Point3D)
. Similarly, in your case, use an RGB class. It may seem silly, but it can save some annoying errors (e.g., if you have functions that take ints and RGBs), and time (if you have to pass the values to other functions). You can create a static factory method to make these types easier to create when passing arguments.
For example: doSomethingWithColor(RGB.create(20,30,40))
Solution 3:[3]
There's probably no reason to have a class to wrap these functions if they don't logically belong to a class. In that case you can just have them be free functions. It might be appropriate to contain them in a namespace to help avoid name collisions.
If you want to provide a stringer logical grouping of the classes, there's no real harm in having them be static member functions of a class - but I see no reason why you'd have functions like MapRGB()
and CopyString()
need to be members of the same class.
Solution 4:[4]
If you just want to group functions together, but not create an instance of the group, then you should probably be thinking of putting them into a namespace rather than a class at all.
I would try to use meaningful namespaces though -- putting MapRGB and CopySstring together makes very little sense. If you really need both, and really don't have any other functions that deal with strings or RGB mapping, putting them into a "utillity" namespace might make sense, but if you're using those, it seems like that you have some more string "stuff" and some more "color" stuff, and could probably benefit from having a namespace for each.
Solution 5:[5]
I generally have a .a (.lib on windows) called "util" that gets linked in. However, usually a "util" class is bad news, and it introduces a dependency that breaks standard object-oriented design. Now, if you try to pull out a class to reuse in a different project, you have thousands of hidden dependencies on your util library. Basically, it's useful, but do your very best to avoid putting things in there.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | James McNellis |
Solution 2 | |
Solution 3 | Michael Burr |
Solution 4 | Jerry Coffin |
Solution 5 | Clark Gaebel |