在Java中使用枚举时如何避免过多的代码重复

我正在重构一些遗留代码并遇到了一个问题,我确信它有一个优雅的解决方案 – 但我无法完全实现.

最初有一大堆类扩展了抽象类BaseType.这些类中的每一个都有一个枚举 – XmlElementTag – 具有特定于该类的值:

enum XmlElementTag {value1, value2, value3}

他们每个人都有一个方法:

private XmlElementTag getTag(String s){
    XmlElementTag ret = null;
    try {
        ret = XmlElementTag.valueOf(s);
    } catch (Exception e) {
        Log.e(this, s+" is not supported tag");
    }
    return ret;
}

每个类都有这个完全相同的getTag方法,但显然它们都是指特定于它们所在类的XmlElementTag枚举.所以,如果可以的话,我想摆脱这个代码重复.

我想也许我可以使用一个标记接口来解决这个问题,所以创建一个,每个XmlElementTag枚举现在继承并重写getTag方法并将其放在超类中.

所以我在每个班级都有这个:

private XmlElementTag implements GenericTag {value1, value2, value3}; 

这在BaseType超类中:

public interface GenericTag {}

protected GenericTag getTag(String tagName){
    XmlElementTag tag = null;
    try {
        tag = XmlElementTag.valueOf(tagName);
    } catch (Exception e) {
        Log.e(this, tagName+" is not supported tag");
    }
    return tag;
}

但同样这不起作用,因为BaseType超类不知道XmlElementTag是什么; Java不允许抽象类变量;并且在BaseType中创建此元素将不起作用,因为getTag代码将始终引用此枚举,而不是扩展BaseType的类中的那个.

谁能指出我正确的方向?

最佳答案
不幸的是,Java枚举没有一个好的元类(类是邪恶的).但是,这里你真正需要的是枚举值的列表(数组).

因为它是一种私有方法,你不妨使用组合.

import static java.util.Objects.requireNonNull;

/* pp */ class EnumFinder<E extends Enum<E>> {
    private final E[] tags;
    protected BaseType(E[] tags) {
        this.tags = requireNonNull(tags);
    }

    public E getTag(String name) {
        requireNonNull(name);
        for (E tag : tags) {
            if (name.equals(tag.name())) {
                return tag;
            }
        }
        Log.e(this, name+" is not supported tag"); // (sic)
        return null; // (sic)
    }
    ...
}

public class DerivedType {
    private static final EnumFinder<XmlElementType> finder = // note, shared
        new EnumFinder<>(XmlElementType.values());
    ...
        finder.getTag(name)
    ...
}

(创建一个Map< String,E>如果你真的想要.对于合理大小的枚举,这是不必要的.)

如果你真的想使用继承,那就大致相同了. (不幸的是,因为我们正在使用数组,除非你在代码中添加更多样板文件,否则这个代码会为每个实例创建一个不必要的额外数组 – 可能不是一个重要的问题,但可能是.):

/* pp */ abstract class BaseType<E extends Enum<E>> {
    private final E[] tags;
    protected BaseType(E[] tags) {
        this.tags = requireNonNull(tags);
    }

    public E getTag(String name) {
        requireNonNull(name);
        for (E tag : tags) {
            if (name.equals(tag.name())) {
                return tag;
            }
        }
        Log.e(this, name+" is not supported tag"); // (sic)
        return null; // (sic)
    }
    ...
}
public class DerivedType extends BaseType<XmlElementType> {
    public DerivedType() {
        super(XmlElementType.values());
    }
    ...
        this.getTag(name)
    ...
}

转载注明原文:在Java中使用枚举时如何避免过多的代码重复 - 代码日志