Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and how should I use enumeration classes rather than enums?

A developer at work recently started using a class pattern instead of enums in places where enums would usually fit. Instead, he uses something similar to that below:

internal class Suit
{
    public static readonly Suit Hearts = new Suit();
    public static readonly Suit Diamonds = new Suit();
    public static readonly Suit Spades = new Suit();
    public static readonly Suit Clubs = new Suit();
    public static readonly Suit Joker = new Suit();
    private static Suit()
    {

    }
    public static bool IsMatch(Suit lhs, Suit rhs)
    {
        return lhs.Equals(rhs) || (lhs.Equals(Joker) || rhs.Equals(Joker));
    }
}

His reasoning is that it invisibly looks like an enumeration, but allows him to contain the methods relating to the numeration (like the IsMatch above) to be contained within the enumeration itself.

He called this an Enumeration class, but it's not something I've ever seen before. I wondered what the advantages and disadvantages were and where I could find out more information?

Thanks

Edit: Another advantage he described was being able to add a specific ToString() implementation for the enumeration.

like image 407
Chris Williams Avatar asked May 12 '13 12:05

Chris Williams


2 Answers

Enums are just fine in lots of scenarios, but quite poor in others. Usually I find some issues with Enums :

  • Behavior related to the enumeration gets scattered around the application
  • New enumeration values require shotgun surgery
  • Enumerations don’t follow the Open-Closed Principle

With enumeration behavior scattered around, we can never bring it back to the source type, because enumeration types can’t have any behavior (or state for that matter).

In the other hand with an Enumeration Class:

All of the variations of each enumeration type can be pushed down not only to the enumeration class, but to each specific subtype.

Enumerations work well in a variety of scenarios, but can break down quickly inside your domain model. Enumeration classes provide much of the same usability, with the added benefit of becoming a destination for behavior.

Switch statements are no longer necessary, as I can push that variability and knowledge where it belongs, back inside the model. If for some reason I need to check specific enumeration class values, the option is still open for me. This pattern shouldn’t replace all enumerations, but it’s nice to have an alternative.

can read on that here

like image 141
Rawdreeg Avatar answered Oct 08 '22 15:10

Rawdreeg


The main advantage of enums is that they are basically integers with some named values, as such they are inherently portable and serializable. Arithmetic and logical operations are also faster on enums.

Enumeration classes are used when you need an opaque value which has extra state information. For instance a generic Data Access Layer could have as an interface like:

public static class Dal
{
    public static Record Query(Operation operation, Parameters parameters);
}

var result = Dal.Query(Operation.DoSomething, new DoSomethingParameters {...});

To the users of the Dal Operation is just an enumeration of the operations available, but it could contain the connection string, the SQL statement or stored procedure and any other data needed by the generic Dal.

Another "common" use is for public modes in a system (a state or a strategy). From a user perspective the mode is an opaque value, but it may contain information or internal functionality crucial to the implementation of the system. A contrived example:


public class TheSystem
{
   public SystemMode Mode;
   public void Save()
   {
      Mode.Save();
   }
   public SystemDocument Read()
   {
      return Mode.Read();
   }
}

public abstract class SystemMode
{
   public static SystemMode ReadOnly = new ReadOnlyMode();
   public static SystemMode ReadWrite = new ReadWriteMode();

   internal abstract void Save();
   internal abstract SystemDocument Read();

   private class ReadOnlyMode : SystemMode
   {
      internal override void Save() {...}
      internal override SystemDocument Read() {...}
   }

   private class ReadWriteMode : SystemMode
   {
      internal override void Save() {...}
      internal override SystemDocument Read() {...}
   }
}


TheSystem.Mode = SystemMode.ReadOnly;

I don't think just having an IsMatch static method warrants not using simple enums. Something very similar could be achieved with extension methods in this case.

like image 26
Eli Algranti Avatar answered Oct 08 '22 14:10

Eli Algranti