Enum design with many fields

I want to implement an EAN128 barcode parser. In short, an EAN128 barcode is generated by one or more fields, each of which consists of a string identifier and value. There are one hundred different identifiers, and each value has a fixed or variable length (numeric or alphanumeric) depending on the identifier. A variable length value ends with a special char named FNC1.
I want to get all ids and its value from a barcode.
My project is based on an enum with one field for each code id.

public enum IDENT_EAN128 {
  // Identifier 8003 that has a value composed by 14 numeric chars and 1 to 20 alphanumeric chars
  IDENT_8003 ("8003", FixedParser(14, NUMERIC), VariableParser(20, ALPHANUMERIC)),
  IDENT_00   ("00", FixedParser(18, NUMERIC)),

  .... // hundred identifiers

  private IDENT_EAN128 (String code, Parser... parsers ) {
     ...
  }

  public static IDENT_EAN128 search (String code) {
    // loop IDENT_EAN128.values() to search code identifier
  }
}

public class Main {
  public static void test () {
    String id1 = "8003";
    String field1 = "12345678901234";
    String field2 = "12345" + FNC1;

    String id2 = "00";
    String field3 = "123456789012345678";

    String barcode = id1 + field1 + field2 + id2 + field3;
    for (int posBarcode; posBarcode < barcode.length(); posBarcode++) { // loop chars of barcode
      char[] buffer ...
      IDENT_EAN128 idEAN = IDENT_EAN128.search(buffer)
      if (idEAN != null) {
        // loop Parsers for get identifier value
        // move posBarcode to the first barcode position of next identifier
      }
      ....
    }
  }
}

      

The Parsers identifier value returns its length, and the value is of the correct char type (numeric or alphanumeric). The problem with this design is that when called for the first time, it creates hundreds of new objects (each id and its parsers). In most cases, a barcode only has 3 or 4 identifiers. Therefore, I believe that this is time and memory. I have a search on "lazy initialization" design for parsers, but I didn't find one that matches my problem. Is there a better design? or my concern is useless.

thank

+3


source to share


3 answers


I think you can keep the enum approach. But use the enum Singleton function. With that, I mean you only have the INSTANCE multiplication value. Inside your enum, you store the hashmap with the code as a key. Since your method is using code as input. See this:

public enum IDENT_EAN128_CACHE {

  INSTANCE;

  private static final Map<String, ParserStore> storage = new HashMap<>();

  public synchronized IDENT_EAN128 search (String code) {

    // If the code is already in the map return the needed values 

    // Else lazy initialize the hashmap entries if the requested entry is not contained and return it.

    return 'the value you should return';

    }

}

      

Then you can access the following functions:

IDENT_EAN128.INSTANCE.search("some code");

      



Edit

With this design, you won't be able to store IDENT_EAN128 as an Enum if you want to be lazy to initialize it. This should be an object initialized by the "enum cache" I provided for the code.

Edit 2 . Code modifications suggested by Mike Straubel in the comments.

+1


source


For the most part, your design is good, although I would use a statically constructed map to do the search rather than looping over values()

. I wouldn't bother with the extra memory or cpu cycles involved in creating a couple hundred extra objects. They are only created once per JVM, so it doesn't matter if the objects are not mammoths, or if you've been running 286 since 1990. A clear design is more important. Note that I am also assuming VariableParser

both FixedParser

are classes and have inserted a keyword in front of them new

to invoke the constructors.

You can fill codeMap

lazily if you like, but that won't buy you much. Since all the objects have already been created, you will simply save a tiny bit of initialization when creating entries in the Map.



public enum IDENT_EAN128 {
    // Identifier 8003 that has a value composed by 14 numeric chars and 1 to 20 alphanumeric chars
    IDENT_8003 ("8003", new FixedParser(14, NUMERIC), new VariableParser(20, ALPHANUMERIC)),
    IDENT_00   ("00", new FixedParser(18, NUMERIC));
    // ... hundred identifiers

    private static final HashMap<String, IDENT_EAN128> codeMap = new HashMap<String, IDENT_EAN128> ();
    static {
        for(IDENT_EAN128 ident: IDENT_EAN128.values()) {
            codeMap.put(ident.getCode(), ident);
        }
    }

    private String code;

    private IDENT_EAN128 (String code, Parser... parsers ) {
        this.code = code;
        // do something with parsers as well...
    }

    public String getCode() {
        return code;
    }

    public static IDENT_EAN128 search (String code) {
        return codeMap.get(code);
    }
}

      

0


source


Thank you for your responses. After looking at them, I decided to keep the Enumeration project, but added Matt's HashMap suggestion and lazy initialization of parsers in each id. So the code looks like this:

public enum IDENT_EAN128 {
  // Identifier 8003 that has a value composed by 14 numeric chars and 1 to 20 alphanumeric chars
  IDENT_8003 ("8003") {
    @Override public Parser[] getParsers () {
      return new Parser[]{new FixedParser(14, NUMERIC), new VariableParser(20, ALPHANUMERIC)};
    }
  },

  .... // hundred identifiers

  private static final HashMap<String, IDENT_EAN128> codeMap = new HashMap<String, IDENT_EAN128> ();
  static {
    for (IDENT_EAN128 ident: IDENT_EAN128.values())
      codeMap.put(ident.getCode(), ident);
  }

  private IDENT_EAN128 (String code) {
   ...
  }

  public static IDENT_EAN128 search (String code) {
    return codeMap.get(code);
  }

  public abstract Parser[] getParsers ();
}

      

0


source







All Articles