如何避免在地图中为包装器对象进行转换?

时间:2012-12-18 23:18:39

标签: java interface casting

我有一个FeatureValue接口,它实现了一个名为pretty print的函数。

我现在有两个实现该接口的类:FeatureString和FeatureList(FeatureList中的列表包含字符串)。这些类只是分别存储字符串和列表的包装器,并为它们的包装值实现了漂亮的print函数。

我有EnumMap,它将一些Feature类型的枚举作为键(一些对应于字符串,一些对应于列表)。

我最初创建了这个界面,以便我可以遍历枚举并打印它们。但现在我希望能够从包装器FeatureValue中获取值。

由于我将枚举映射存储为<Feature, FeatureValue>,因此它不知道包装值是什么类型,所以当我得到它时我必须进行转换。

有没有办法重构我的代码,这样我就不需要进行强制转换,但仍然可以在不知道类型的情况下迭代枚举并打印它们?

枚举

public enum Features
{
KIND("kind"),
RULE("rule"),
PROBLEM("problem"),

private String name;

Features(String name)
{
    this.name = name;
}

public String getName()
{
    return name;
}
}

接口

public interface FeatureValue
{
    public String prettyPrint();
}

列表实现(FeatureString有一个类似的,我将省略)

public class FeatureList implements FeatureValue
{
private final List<String> list;

public FeatureList(List<String> list)
{
    this.list = list;
}

@Override
public String prettyPrint()
{
    return Arrays.toString(list.toArray());
}

public List<String> getList()
{
    return list;
}
} 

投射代码

for(String token: ((FeatureList) enumMap.get(Feature.particularFeatureThatCorrespondsToLists)).getValue())
    doSomething(token);

由于地图是针对Feature的值而非FeatureList

的参数化,因此需要进行强制转换

2 个答案:

答案 0 :(得分:0)

将方法getValue()添加到您的界面FeatureValue,并使界面参数化。

FeatureValue.java

public interface FeatureValue<E> {

    String prettyPrint();    

    E getValue();

}

FeatureList.java

public class FeatureList implements FeatureValue<List<String>> {    

    private final List<String> list = new ArrayList<String>();

    public String prettyPrint() {
        return list.toString();
    }

    public List<String> getValue() {
        return list;
    }

}

Main.java

public static void main( String[] args ) {
    for (String each: getAsList(enumMap, Features.KIND)) {
        // do stuff
    }
}

private static List<String> getAsList(
        EnumMap<Features, FeatureValue> enumMap, Features key) {
    FeatureValue value = enumMap.get(key);
    return value != null ? 
       ((FeatureList) value.getValue()).getValue() : Collections.EMPTY_LIST;
}

答案 1 :(得分:0)

制作你的

public interface FeatureValue
{
    public String prettyPrint();
}

可迭代,像这样

public interface FeatureValue extends Iterable<String>
{
    public String prettyPrint();
}

这将使任何FeatureValue可以通过foreach循环进行迭代。

对于实际上不需要迭代的类,要么抛出异常

public class Stubbed1 extends FeatureValue {
    public Iterator<String> getIterator() {
        throw new UnsupportedOperationException();
    }
}

或返回一个空的迭代器

public class Stubbed2 extends FeatureValue {
    public Iterator<String> getIterator() {
        return Collections.<String>emptyList().iterator();
    }
}

对于需要迭代的类,请执行以下操作

public class DocumentFeatureList implements FeatureValue
{
   private final List<String> list;

   ...

   public Iterator<String> getIterator() {
       return list.iterator();
   }
}