Utility Classes are edevil

Source: Internet
Author: User
Tags addall
What's Utility Classes

A utility class is a class filled with static methods. It is usually used to isolate a "useful" algorithm.

StringUtils,IOUtils,FileUtilsFrom Apache commons;IterablesAndIteratorsFrom guava, andFilesFrom jdk7 are perfect examples of Utility Classes.

Why Utility Classes

If you have two classesAAndB, And have a methodf()That both must use, then the most naive approach is to repeat the function as a method in both classes. However, this violates the don't repeat yourself (dry) approach to programming.

The most natural solution is inheritance, but it's not always beneficialAAndBTo be subclasses of some parent class. In my case,AWas already a subclass of another class, whileBWas not. There was no way to makeAAndBSubclasses of a parent class without breaking that other relationship.

The alternative is to define the Utility Class: a public static class that sits in the global namespace, awaiting anyone to "borrow" them.

They are not bad in themselves, but they do imply relationships between your data that are not explicitly defined. Also, if your static class has any static variables, thenAAndBNever really know what they're getting into when they use it.

Disadvantage

However, in an object-oriented world, Utility Classes are considered a very bad practice.
The use of utility classes to be an antipattern. More specifically, it violates common design principles:

Single Responsibility Principle

A class shoshould have one and only one reason to change

You can design Utility Classes where all of the methods related to a single set of responsibilities. that is entirely possible. therefore, I wocould note that this principle does not conflict with the notion of Utility Classes at all.
That said, I 've often seen helper classes that violate this principle. they become "catch all" classes (or God classes) that contain any method that the developer can't find another place. (e.g. A class containing a helper Method for URL encoding, a method for looking up a password, and a method for writing an update to the config file... This class wocould violate the single responsibility principle ).

Liskov substitution principle

Derived classes must be substitutable for their base classes

This is kind of a no-op in that a utility class cannot have a derived class. OK. Does that mean that Utility Classes violate LSP? I 'd say not. A helper class looses the advantages of OO completely, an in that sense, LSP doesn't matter... But it doesn' t violate it.

Interface segregation principle

Class interfaces shoshould be fine-grained and client specific

Another no-op. Since Utility Classes do not derive from an interface, it is difficult to apply this principle with any degree of seperation from the single responsibility principle.

The open closed Principle

Classes shoshould be open for extension and closed for Modification

You cannot extend a utility class. since all methods are static, you cannot derive anything that extends from it. in addition, the code that uses it doesn't create an object, so there is no way to create a child object that modifies any of the algorithms in a utility class. they are all "unchangable ".

As such, a helper class simply fails to provide one of the key aspects of Object Oriented Design: the ability for the original developer to create a general answer, and for another developer to extend it, change it, make it more applicable. if you assume that you do not know everything, and that you may not be creating the "perfect" class for every person, then Utility Classes will be an anathema to you.

The dependency inversion principle

Depend on effecactions, not concrete implementations

This is a simple and powerful principle that produces more testable code and better systems. if you minimize the coupling between a class and the classes that it depends upon, you produce code that can be used more flexibly, and reused more easily.

However, a utility class cannot participant in the dependency inversion principle. it cannot derive from an interface, nor implement a base class. no one creates an object that can be extended with a helper class. this is the "partner" of the liskov substitution principle, but while Utility Classes do not violate the LSP, they do violate the dip.

In summary, utility classes are not proper objects; therefore, they don't fit into object-oriented world. they were inherited from procedural programming, mostly because most were used to a functional decomposition paradigm back then.

And there are other aritcals about this topic: Are helper classes edevil? By Nick Malik, why helper, Singletons and Utility Classes are mostly bad by Simon Hart, avoiding Utility Classes by partition Al Ward, kill that util class! By dhaval Dalal, helper classes are a code smell by Rob Bagby.

Object-oriented alternativeexample1

Let's takeNumberUtilsFor example:

Utility Class
123456
// This is a terrible design, don‘t reusepublic class NumberUtils {  public static int max(int a, int b) {    return a > b ? a : b;  }}

In an object-oriented paradigm, We shocould instantiate and compose objects, thus lew.them manage data when and how they desire. instead of calling supplementary static functions, we shoshould create objects that are capable of exposing the behaviour we are seeking:

OO class
123456789101112
public class Max implements Number {  private final int a;  private final int b;  public Max(int x, int y) {    this.a = x;    this.b = y;  }  @Override  public int intValue() {    return this.a > this.b ? this.a : this.b;  }}

This procedural call:

1
int max = NumberUtils.max(10, 5);

Will become object-oriented:

1
int max = new Max(10, 5).intValue();
Example2

Say, for instance, you want to read a text file, split it into lines, trim every line and then save the results in another file. This is can be doneFileUtilsFrom Apache commons:

Utility Class
12345678
void transform(File in, File out) {  Collection<String> src = FileUtils.readLines(in, "UTF-8");  Collection<String> dest = new ArrayList<>(src.size());  for (String line : src) {    dest.add(line.trim());  }  FileUtils.writeLines(out, dest, "UTF-8");}


The above code may look clean; however, this is procedural programming, not object-oriented. we are manipulating data (bytes and bits) and explicitly instructing the computer from where to retrieve them and then where to put them on every single line of code. we're defining a procedure of execution.
The oo alternative is:

OO classes
123456789
void transform(File in, File out) {  Collection<String> src = new Trimmed(    new FileLines(new UnicodeFile(in))  );  Collection<String> dest = new FileLines(    new UnicodeFile(out)  );  dest.addAll(src);}

 

FileLinesImplementsCollection<String>And encapsulates all File Reading and Writing operations. An instanceFileLinesBehaves exactly as a collection of strings and hides all I/O operations. When we iterate it-a file is being read. When we addall () to it-a file is being written.

TrimmedAlso implementsCollection<String>And encapsulates a collection of strings (decorator pattern). Every time the next line is retrieved, it gets trimmed.

All classes taking maid in the snippet are rather small:Trimmed,FileLines, AndUnicodeFile.Each of them is responsible for its own single feature, thus following perfectly the single responsibility principle.

On our side, as users of the library, this may be not so important, but for their developers it is an imperative. It is much easier to develop, maintain and unit-test classFileLinesRather than using a readlines () method in a 80 + methods and 3000 lines Utility ClassFileUtils. Seriously, look at its source code.

Lazy execution

An object-oriented approach enables lazy execution. the in file is not read until its data is required. if we fail to open out due to some I/O error, the first file won't even be touched. the whole show starts only after we call addall ().

All lines in the second snippet, couldn't the last one, instantiate and compose smaller objects into bigger ones. This object composition is rather cheap for the CPU since it doesn't cause any data transformations.

Besides that, it is obvious that the second script runs in O (1) space, while the first one executes in O (n ). this is the consequence of our procedural approach to data in the first script.

In an object-oriented world, there is no data; there are only objects and their behavior!

References

Http://www.javacodegeeks.com/2014/09/oop-alternative-to-utility-classes.html http://blogs.msdn.com/ B /nickmalik/archive/2005/09/06/461404.aspx http://www.marshallward.org/avoiding-utility-classes.html

 

Address: http://alphawang.com/blog/2014/09/utility-classes-are-evil/

Utility Classes are edevil

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.