2

Is it possible to use an enumeration in the following circumstance:

Let’s say you have a certain amount of predefined 'read types'. Example read types could be: Diagnostic, KWH, MaxDemand, OnPeak, etc. And for each of these read types, there’s a ‘TIMTagNumber’ which is essientally a protocol for retrieving each predefined read type.

For example, TIMTagNumber 1100 would retrieve the read type Diagnostic TIMTagNumber 1300 would retrieve the read type KWH. The problem is that a predefined read type can sometimes be retrieved by more than one TIMTagNumber.

I want to create an enumeration ReadType that would define each read type and all TIMTagNumbers that can be used to retrieve that read. Can you use an enumeration in this way?

public enum ReadType{
    KWH(1300)
    Diagnostic(1100)
    ReadType3(1400, 1401) // This read can be retrieved by both 1400 and 1401
}

If an enumeration is not the way to go, is there an elegant or efficient way to define these read types? The overall desired outcome of all this essientally is being recognizing what type of read it is based on the TIMTagNumbers.

I.E. Given 1400 OR 1401 you would know that it's 'ReadType3'.

TyC
  • 792
  • 6
  • 11
  • 23

5 Answers5

4

Can you do this? Yes. Whether it's the right decision will depend on whether you want to couple these TIMTagNumbers to the read type. If not, a simple Map<Integer, ReadType> will probably suffice.

Here's how you could do it:

public static enum MyEnum {
    KWH(1300), 
    Diagnostic(1100),
    ReadType3(1400, 1401);

    private Set<Integer> timTagNumbers;

    MyEnum(Integer... timTagNumbers) {
        this.timTagNumbers = new HashSet<Integer>(Arrays.asList(timTagNumbers));
        //add check to make sure that values are unique across all instances
    }

    public static MyEnum forTIMTagNumber(int num) {
        for ( MyEnum readType : values() ) {
             if ( readType.timTagNumbers.contains(num) ) {
                 return readType;
             }
        }
        throw new NoSuchElementException("No ReadType matching TIMTagNumber " + num);
    }
}

//...
int timTagNumber = 1400;
ReadType readType = ReadType.forTIMTagNumber(timTagNumber);

As I said above, this style works well when the data and the enum types are intrinsically coupled already. It would not be good for when the enum type is decoupled from the mapped values (e.g. the values are used for one of many ways of serializing the enum) or if the values are configuration-specific or even dynamic (e.g. if they were prices on an item). In these cases it is usually best to externalize this mapping in an EnumMap or Map.

Mark Peters
  • 80,126
  • 17
  • 159
  • 190
  • So far this looks good! I'm going to give it a try. One question though, I'm not super fimiliar with the enhanced for loop, especially in the way you used it. What does 'values()' represent and where is it defined? – TyC Mar 16 '12 at 18:30
  • 2
    @TyC Every enum type has a `values()` method, returning an ordered array of the enum's values, see [documentation](http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html). The `for (x : y)` is a short form for `for (int i = 0; i < y.length; i++) { x = y[i] }` and works for arrays and `Iterable>` – jabu.10245 Mar 16 '12 at 18:34
3
public enum ReadType {
    KWH(1300),
    Diagnostic(1100),
    ReadType3(1400, 1401);

    private int[] timTagNumbers;

    private ReadType(int ... numbers) {
        this.timTagNumbers = numbers;
    }

    public int[] getTimTagNumbers() {
        return timTagNumbers;
    }

    public static ReadType forTimTagNumber(int n) {
        for (ReadType type : values()) {
            if (Arrays.binarySearch(type.timTagNumbers, n) != -1) {
                return type;
            }
        }

        throw new NoSucheElementException();  // if not found
    }

With this you can do

int[] timTagNumbers = ReadType.Diagnostic.getTimTagNumbers();  // [ 1100 ]

and

ReadType type3 = ReadType.forTimTagNumber(1401);  // ReadType.ReadType3
jabu.10245
  • 1,884
  • 1
  • 11
  • 20
0

You can indeed use enumerations in that way, but your example is missing a private field and a constructor.

Something like:

public enum Bla{
    CASE1(100),CASE2(200);

    private int amount;

    private Bla(int amount) {
        this.amount = amount;
    }

    public Bla getByValue(int value){
        switch (value) {
            case 100: return CASE1;
            case 200: return CASE2;
        }
        return null;
    }

}

I've included a "reverse lookup" method that returns an Enum given the value.

The main advantage is that you can have the rest of your code using "Bla" instead of int's which will guarantee type-safety on your operations, basically, it'll make impossible to pass an invalid int value as a method parameter (and you can use switch statements over enums too, and that's pretty awesome in some usage scenarios).

EDIT: I noticed after I posted that you need more then one int to specify the Enum, but the same logic applies, with the due changes in the methods, of course.

pcalcao
  • 15,789
  • 1
  • 44
  • 64
0

You could do something like the following, when you supply values in the parentheses where the enum variable is declared, it is calling the constructor of the enum. You need to create a different method in the enum itself to get the enum type from the integer value. See below.

public enum ReadType {
        KWH(), DIAGNOSTIC(), READTYPE3();

        public ReadType getReadType(int num) {
            ReadType toReturn = KWH;
            switch (num) {
            case 1300:
                toReturn = KWH;
                break;
            case 1100:
                toReturn = DIAGNOSTIC;
                break;
            case 1400:
                toReturn = READTYPE3;
                break;
            case 1401:
                toReturn = READTYPE3;
                break;
            }
            return toReturn;

        }
Reid Mac
  • 2,411
  • 6
  • 37
  • 64
0

If you can impose some restrictions like no more than 2 tags can be associated with a read type and each tag is no greater than 2^15, then you can store the two numbers into 1 integer. See this S/O post for more details.

Community
  • 1
  • 1
blackcompe
  • 3,180
  • 16
  • 27