0

I'm Working with php and we using enum's by create an Abstract class that mocking enum behavior - but my question is cross-languages.

Where all the helper functions like toString, getEnumTypes, checkValidValue, etc... should be, in a dedicated utility class: EnumUtil or in the AbstractEnum it self (all enums extends AbstractEnum so all enum have those functions)

And if the answer it in the AbstractEnum itself in which cases I should create a utility class?

P.S: This is a general question but I focused it with a real life example.

Michael
  • 187
  • 1
  • 8
  • I'm not clear what you mean by "enums" with respect to PHP. Are you using an abstract base class, with concrete child classes, in combination with protected and private constructors on those classes to give you only certain instances of those classes? – Greg Burghardt Jul 19 '17 at 14:56
  • 1
    We are using a class like that one: [AbstractEnum](https://github.com/facebook/facebook-php-ads-sdk/blob/master/src/FacebookAds/Enum/AbstractEnum.php), so we don't have instances of enums rather than we using it as static class – Michael Jul 19 '17 at 16:46

3 Answers3

4

If the functions are meaningful for all enums, then use the base class.

"Utility classes" in general should be avoided. Or to put it another way, if you can only think of the name FooUtility for a class, then the functionality probably belongs in Foo rather than in a seperate class.

Edit: Obviously this depends on your definition of "utility class", since it is not a term with an absolute definition. But if the sole purpose of a class is to provide utility functions for operations on another class - as in your example - then the functions belongs on that class. Only justification I can think of for a separate class is utility functions for a sealed class.

JacquesB
  • 57,310
  • 21
  • 127
  • 176
  • Sorry, had to downvote because of the bad advice that utility classes should be avoided. See my answer with a well-justified problem where the natural solution is to use in fact a utility class for utilities operating on objects implementing a given interface. As John Carmack has said, "Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function." – juhist Jul 19 '17 at 13:42
  • 1
    @juhist: I'm not sure the Carmack quote can be used to justify creating a redundant class. That said, "Utility classes" can be justified depending on the purpose of the class (I don't think there is an objective definition of the term "utility class" anyway.). But if a class *only* works as a utility for another class, as in the question, then it is superfluous. Only justification I can think of is for extension methods for a sealed class. – JacquesB Jul 19 '17 at 15:15
  • "Utility class" is a phrase I have only ever heard used to collect common functionality across classes, not a place to stuff code because a single class became larger. – Frank Hileman Jul 19 '17 at 16:21
  • Thanks, @JacquesB what do you think about FileUtil? do you think it's a problematic too? yes, we can vreate a File class that have path, size and whatever but most of the time we just need to do operations like `rename` or `getSize` and not really need a full (heavy?) object. – Michael Jul 19 '17 at 16:56
  • @Michael: If you are talking about static methods versus instance methods, this is an independent issue. – JacquesB Jul 20 '17 at 07:13
  • @JacquesB yeah, but what's wrong with FileUtil? – Michael Jul 20 '17 at 08:16
  • @Michael: Why would you introduce a FileUtil when you already have File? – JacquesB Jul 20 '17 at 08:50
0

Any and all methods which make sense to be applied directly to a enum value should be in AbstractEnum such as toString. Static methods like retrieving a value from a string (valueOf in Java) could either be placed in a helper class or placed directly in the derived enum class (though I would avoid placing it in AbstractEnum for simplicity's sake).

Ideally, the constructor of AbstractEnum and all derived classes would be protected and instantiated only by the class itself in a static fashion, so that there's no possibility of checking equality between separate instances of the same "enum value".

However as a general rule of thumb, you should place methods in AbstractEnum only as long as it makes sense to call that method on a specific instance.

Neil
  • 22,670
  • 45
  • 76
0

I would disagree with the generally accepted wisdom that utility classes should be avoided. Using Java here as an example, but I'm sure the idea applies to other languages as well.

Consider, for example, a data type of which you need both mutable (for performance) and immutable (for hash table keys, sets, other kinds of correctness problems, etc.) variants: a complex number. So, you have Complex (immutable) and ComplexBuffer (mutable). Now it would be foolish to write four versions of the subtraction fuctionality (Complex - Complex, ComplexBuffer - Complex, Complex - ComplexBuffer, ComplexBuffer - ComplexBuffer), so you will want to create a common interface ComplexNumber shared by Complex and ComplexBuffer. The ComplexNumber interface has getReal() and getImag() methods.

Now, to subtract two ComplexNumber implementing objects, you will define a class ComplexUtils and a static method public static Complex sub(ComplexNumber, ComplexNumber). So, there you have it: a problem where the best solution is to actually use a utility class. Of course, for performance you will have also ComplexBuffer.subInPlace(ComplexNumber) that creates absolutely no new objects.

So, don't follow blindly the advice that utility classes should be avoided. As John Carmack has said:

Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
juhist
  • 2,579
  • 10
  • 14
  • 1
    But you *are* creating a new class, the utility class. Why can't you add the methods in question to the base class? – JacquesB Jul 19 '17 at 14:34
  • It's a base interface, not a base class. Interfaces cannot have methods. – juhist Jul 19 '17 at 14:35
  • The other alternative is to eliminate the mutable Complex entirely. And this is typically what is done. Perhaps your example would make more sense with a different type. In this case you have collected common code into a utility class, whereas in the original question, it appears that the utility class had code used by only a single other class. – Frank Hileman Jul 19 '17 at 16:25
  • In any case this could be solved more elegantly by using a base class or some other device (default interface methods in Java?). There is no reason the consumer of complex numbers should need to know about "ComplexUtils" if they already have a complex number instance. – JacquesB Jul 19 '17 at 16:31
  • I think you could replace ComplexNumber with CharSequence, Complex with String, ComplexBuffer with StringBuffer / StringBuilder and the example then makes more sense if you don't care about complex number micro-optimizations like I do. The place to add a newly written character sequence algorithm would be appropriately called CharSequenceUtils. – juhist Jul 19 '17 at 16:53
  • The better solution to this as @JacquesB said is to have a base class. Just to respond to the fact that it uses a base interface, the correct solution is to add an abstract base class in between the interface and concrete class. I think this is actually a good example of @JacquesB mentioned in their answer " if you can only think of the name `FooUtility` for a class, then the functionality probably belongs in `Foo`". – yitzih Jul 19 '17 at 17:32