【问题标题】:How to avoid casting for wrapper objects in maps?如何避免在地图中转换包装对象?
【发布时间】:2012-12-18 23:18:38
【问题描述】:

我有一个接口 FeatureValue,它实现了一个叫做漂亮打印的函数。

我现在有两个实现该接口的类:FeatureString 和 FeatureList(FeatureList 中的列表包含字符串)。这些类只是包装器,分别存储一个字符串和一个列表,并为其包装的值实现漂亮的打印功能。

我有 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();
}

List 实现(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 参数化的,因此需要进行强制转换

【问题讨论】:

  • 我们能看到一些代码吗?看起来您缺少一些东西,例如您“将枚举映射存储为”。
  • 是的,我刚刚注意到,我修复了缺失的部分
  • 好的,我已经添加了一些代码
  • 您向我们展示了FeatureValueFeatureString,但您的问题在于FeatureListFeatureenumMap。请向我们展示正确的代码;)
  • 好的,我添加了更多代码。我不确定你说 enumMap 时指的是什么代码,我已经在 Casting Code 下找到了它。

标签: java interface casting


【解决方案1】:

做你的

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();
   }
}

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 我没有实例化 FeatureList,我是从包含 FeatureValues 的地图中获取它们,这就是为什么我首先需要演员表。
    • 没错,演员阵容仍然需要。我唯一能想到的就是创建一个方法来进行转换,这将使代码更清晰。恐怕强制转换总是必要的,因为您的地图存储了一个接口,返回的值取决于该接口的实际实现。编辑了我的代码
    猜你喜欢
    • 1970-01-01
    • 2016-02-19
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 2017-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多