Creating a Catch-All AppToolbox class is bad practice?

Not sure where to place features like:

String PrettyPhone( String phoneNumber ) // return formatted (999) 999-9999 String EscapeInput( String inputString ) // gets rid of SQL-escapes like ' 

I create a Toolbox class for each application that serves as a repository for functions that do not fit neatly into another class. I read that such classes are bad programming practice, especially poor object-oriented design. However, the links mentioned seem to be more the opinion of individual designers and developers than excessive consensus. So my question is: the elusive design pattern? If so, why and what alternative is there?

+6
c # oop
source share
8 answers

Great question. I always believe that for any fairly complex project, classes of "utility" are required. I think this is simply because the nature of object-oriented programming forces us to put things in a neatly structured hierarchical taxonomy when it is not always possible or appropriate (for example, try creating an object model for mammals and then squeezing the platypus in). This is a problem that motivates work in aspect-oriented programming (cf cross cutting care ). Often, what is included in the utility class is things that are cross-cutting issues.

One use case for toolbars or utility classes is to use extension methods to provide additional necessary functions to primitive types. However, the jury still does not know if this is a good software design.

My last word on this subject: go with him if you need to, just make sure that you are not short best projects. Of course, you can always reorganize later if you need to.

+6
source share

In these examples, I would be more likely to extend String:

 class PhoneNumber extends String { public override string ToString() { // return (999) 999-9999 } } 

If you write down all the places you need, you can understand what actually uses it, and then add it to the appropriate class. Sometimes it can be difficult, but still you should strive for it.

EDIT:

As indicated below, you cannot override String in C #. What I tried to do is that this operation is performed by phone number, so the function belongs to:

 interface PhoneNumber { string Formatted(); } 

If you have different formats, you can exchange PhoneNumber implementations without clogging your code with if statements, for example,

Instead:

 if(country == Countries.UK) output = Toolbox.PhoneNumberUK(phoneNumber); else ph = Toolbox.PhoneNumberUS(phoneNumber); 

You can simply use:

 output = phoneNumber.Formatted(); 
+2
source share

I think a static helper class is the first thing that comes to mind. It is so common that some even refer to it as part of an object-oriented design. However, the biggest problem with helper classes is that they tend to become a big dump. I think I saw how this happened on several larger projects in which I participated. You are working on a class and donโ€™t know where to use this and this function so that you put it in your helper class. At this point, your assistants are poorly informed of what they are doing. The name "helper" or "util" in the class name does not mean anything. I think that almost all OO gurus oppose helpers, as you can easily replace them with more descriptive classes if you think well enough. I tend to agree with this approach, because I believe that assistants violate the principle of shared responsibility. Honestly, take this with salt. I am a little inclined towards OOP :)

+2
source share

There is nothing wrong. It is one thing to break it into logical parts. By doing this, you can keep your intellisense clean.

 MyCore.Extensions.Formatting.People MyCore.Extensions.Formatting.Xml MyCore.Extensions.Formatting.Html 
+1
source share

My experience is that utility functions are rarely found in isolation. If you need a way to format phone numbers, you will also need one for checking phone numbers and parsing phone numbers. Following the YAGNI principle, you certainly wouldnโ€™t want to write such things until you need them, but I think itโ€™s useful to just continue and separate these functions into separate classes. The growth of these classes from individual methods to secondary subsystems will occur naturally over time. I found this to be the easiest way to keep the code organized, understandable, and maintained in the long run.

+1
source share

When I create an application, I usually create a static class that contains static methods and properties that I cannot figure out where to put elsewhere.

This is not a very good design, but this is what: it gives me a place to localize a whole class of design decisions that I have not yet thought through. As a rule, when an application grows and is refined through refactoring, it becomes clearer where these methods and properties should really be located. Fortunately, the state of the refactoring tools is such that these changes are usually not exclusively painful.

I tried to do it differently, but the other way basically implements the object model before I know enough about my application for the proper development of the object model. If I do this, I will spend a lot of time and energy coming up with a mediocre solution that I must reconsider and rebuild from scratch at some point in the future. Well, well, if I know that I will refactor this code, how about skipping the design phase and creating unnecessary complex classes that actually don't work?

For example, I created an application that is used by several clients. I realized quite early that I needed to have a way to separate methods that should work differently for different clients. I built a static utility method that I could call at any time in the program where I needed to call a custom method, and got stuck in my static class.

This worked perfectly for several months. But there came a time when he was just starting to look ugly. And so I decided to reorganize it into my class. And when I looked through my code, looking at all the places where this method was called, it became completely clear that all the configured methods really should be members of an abstract class, client assemblies should contain one derived class that implements all abstract methods, and then the program is simply necessary to get the assembly name and namespace outside its configuration and instantiate the custom function class at startup. It was very easy for me to find all the methods that needed to be configured, since all I had to do was find all the places that my load-a-custom-feature method called. It took me most of the day to go through the entire code base and streamline this project, and the end result is really flexible and reliable and solves the right problem.

The fact is that when I first applied this method (in fact, it was three or four interconnected methods), I realized that this is not the right answer. But I did not know enough to decide which was the correct answer. So I went with the simplest wrong answer until I got the right answer.

+1
source share

I think the reason he frowned is because the "toolbar" can grow and you will load a ton of resources every time you want to call one function.

Also, itโ€™s more elegant to have methods that apply to objects in a real class โ€” it just makes sense.

If I say that I personally do not consider this a problem, but I avoid it simply for the reasons above.

0
source share

I posted a comment, but thought I would do some more work.

What I am doing is creating a shared library with namespaces: [Organization]. [Product]. Accompany as assistants to the root and secondary namespace.

Several people here mention things like creating a class and shuffling some things that they donโ€™t know where else to put them there. Wrong. I would say that even if you need one helper method, it is associated with something, so create a static helper class with the corresponding name (IoHelper, StringHelper, etc.) and put it in the Helpers namespace. This way you get some structure and you get some sort of separation of problems.

In the root namespace, you can use instance utility classes that require state (they exist!). And, of course, also use the appropriate class name, but not the suffix with Helper.

0
source share

All Articles