【问题标题】:Filtering a collection of inherited objects过滤继承对象的集合
【发布时间】:2012-03-23 03:45:13
【问题描述】:

我有一个基类

public abstract AbstractThing { };

还有很多继承自它的类

public ThingA extends AbstractThing { };
public ThingB extends AbstractThing { };
...
public ThingY extends AbstractThing { };

我有一个 ThingCollector 对象,其中包含一组 Thing 对象,即:

public class ThingCollector {
  public void add(AbstractThing newThing);
}

ThingCollector 类还包含允许:

  1. 查询它持有什么样的具体事物,例如

    public Set<Class<? extends AbstractThing>> containsTypes();

  2. 获取特定具体类型的事物的子集,例如

    public <S extends AbstractMeasurement> Set<S> getSubset(Class<S> type);

目前我的ThingCollector 实现包含Set<AbstractThing> 类型的私有字段。 add(...) 方法将所有内容添加到同一个 Set 对象中。 containsTypes()getSubset(...) 方法在迭代 Set 时使用反射来编织它们的魔力。

这行得通,但看起来很乱。我相信一定有更好的方法!

您能否建议我构建解决方案的其他方法? 我确实考虑让 ThingCollector 为扩展 AbstractThing 的每个单独类型维护一个单独的 Set,但是:

  1. 这意味着ThingCollector 可能包含数十个 Set 对象。在大多数用例中,几乎所有这些集合都是空的。尽管有几十个事物继承自 AbstractThing,但实际上任何给定的 ThingCollector 中只会包含几种不同类型的事物。

  2. 也很乱;每次我在ThingCollector 中定义另一个Set 时,我还需要添加新方法add(ThingZ t)getThingZSubset()

有没有更好的方法? 这里是否有设计模式或不同的类组织可以帮助我?我不依赖上面的接口来查询和子集ThingCollector 的内容 - 所有建议都考虑了!

【问题讨论】:

  • 我还应该补充...虽然 3rd 方库(如建议的番石榴)确实存在,但我想避免在这种情况下使用它们。
  • 你应该展示你的实现代码 - “使用反射编织他们的魔法”不足以让我们知道可以改进的地方。

标签: java oop inheritance collections


【解决方案1】:

如下使用Map<Class,Set>怎么样:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class ThingCollector {

    Map<Class,Set> map = new HashMap<Class,Set>();

    public void add( AbstractThing newThing )
    {
        Class clazz = newThing.getClass();

        Set set = map.get( clazz );
        if ( set == null )
        {
            set = new HashSet();
            map.put( clazz, set );
        }

        set.add( newThing );
    }

    public <S extends AbstractThing> Set<S> getSubset( Class<S> type )
    {
        return map.get( type );
    }
}

使用Guava Multimap 的奖励积分让您的生活更加轻松。

【讨论】:

  • 谢谢。这与我现在的实现非常相似,这让我相信这是一个很好的方法。不幸的是,要获得批准使用像 Guava 这样的第三方库,即使它们是开源的,在工作中还有很多困难。
【解决方案2】:

对于基于类型的过滤元素,您可以使用 Guava 的 Iterables.filter(Iterable, Class),它专门用于此目的。假设ThingCollector 包含一个名为Set&lt;AbstractThing&gt;innerSet

public <S extends AbstractThing> Set<S> getSubset(Class<S> type) {
    return Sets.newHashSet(Iterables.filter(innerSet, type));
}

至于实现containsTypes(),只需遍历每个元素并在其上调用getClass(),将结果添加到返回的Set&lt;Class&lt;? extends AbstractThing&gt;&gt;。或者如果你想花哨,可以使用 Guava 的Iterables.transform(Iterable, Function)

public Set<Class<? extends AbstractThing>> containsTypes() {
    return Sets.newHashSet(Iterables.transform(
          innerSet,
          new Function<AbstractThing, Class<? extends AbstractThing>>() {
              @Override
              public Class<? extends AbstractThing> apply(AbstractThing thing) {
                  return thing.getClass();
              }
          }));
}

免责声明:示例未经测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-21
    • 2017-02-04
    • 1970-01-01
    • 2011-10-05
    • 2016-12-13
    • 1970-01-01
    • 2013-01-17
    • 2011-12-12
    相关资源
    最近更新 更多