2014-09-02 97 views
3

我想实现一个EAN128条形码分析器。简而言之,EAN128条码由一个或多个字段构成,每个字段由一个字符串标识符和一个值组成。有一百个不同的标识符,每个值具有固定或可变长度(数字或字母数字)取决于标识符。可变长度值以名为FNC1的特殊字符结束。
我想从条形码中获取所有标识符及其值。
我的设计基于枚举,每个代码标识符都有一个字段。有很多字段的枚举设计

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 = "123456789"; 
    String field2 = "12345" + FNC1; 

    String id2 = "00"; 
    String field3 = "123456789"; 

    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 
     } 
     .... 
    } 
    } 
} 

解析器返回标识符值,验证其长度并且该值具有正确的字符类型(数字或字母数字)。 这个设计的问题是,当第一次被调用时,它会创建数百个新对象(每个标识符和它的解析器)。大多数时候条形码只有3或4个标识符。所以,我认为这是时间和记忆的一种滋味。我搜索解析器的“懒惰inizialitation”设计,但我还没有找到与我的问题相对应的东西。有更好的设计吗?或者我的担心是没有用的。

谢谢

回答

1

我认为你可以保持enum方法。但要利用枚举Singleton特性。这意味着你只需要和INSTANCE枚举值。在你的枚举中,你保存了一个hashmap,代码是key。由于您的方法使用代码作为输入。看到这一点:

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'; 

    } 

} 

然后,您可以访问这样的功能:

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

编辑

有了这个设计,你不能保持IDENT_EAN128作为一个枚举,如果你想懒惰初始化它。它应该是一个由我提供代码的“枚举缓存”初始化的对象。

编辑2:由Mike Strobel在评论中提出的代码修改。

+0

那么“存储”映射中的值实际上会被读取和返回吗? 'search'方法是否只返回'INSTANCE'? – 2014-09-02 14:37:15

+0

使用地图存储解析器对象似乎是一个好主意,我只有两个Parser对象的对象实例。但它是否安全?正如马特所说,我没有看到如何从搜索方法中获得标识符。 – user1151816 2014-09-02 15:04:46

+0

请参阅我的文章的编辑。我澄清了搜索功能中的逻辑。因此,如果代码包含在地图中,则返回所需的内容,否则将其初始化。对于线程安全来说,锁现在保护对hashmap的访问。 – Esquive 2014-09-02 15:18:35

0

大多数情况下,您的设计很好,但我会使用静态构建的地图来进行搜索,而不是循环播放values()。我不担心额外的内存或CPU周期与创建几百个额外的对象有关。它们只能为每个JVM创建一次,除非对象是庞然大物,或者如果从1990年开始运行286,那么没有什么大不了的。清晰的设计更重要。请注意,我还假设VariableParserFixedParser是类,并在其前面插入new关键字以调用构造函数。

如果你愿意,你可以懒散地填充codeMap,但那不会给你多少钱。由于所有对象都已创建,因此您只需在创建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

谢谢您的回答。考虑到他们之后,我决定继续枚举设计,但在每个标识符中添加HashMap Matt的建议和解析器的惰性初始化。因此,代码如下所示:

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

很高兴您找到您感觉舒适的东西。如果您想要点击答案旁边的复选标记,请随时“接受”答案。 (如果你愿意的话,你甚至可以接受你自己的。)如果你有足够的声望,你也可以提出任何有助于对话的答案。 – 2014-09-08 21:58:29