7

私は3つのインターフェースを持っています:

public interface Combinable<V> {
    V add(V other);
}

public interface Sublistable<V> {
    boolean hasSublist();
    List<V> getSublist();
    void setSublist(List<V> sublist);
}

public interface HasUniqueIdentifier {
    String getUniqueIdentifier();
}

およびこれらのインターフェースの一部またはすべてを実装する4つのクラス:

public class Grandparent implements HasUniqueIdentifier, 
                                    Sublistable<Parent>, 
                                    Combinable<Grandparent> 
{   List<Parent> sublist; ... }

public class Parent implements HasUniqueIdentifier, 
                               Sublistable<Child>, 
                               Combinable<Parent> 
{   List<Child> sublist; ... }

public class Child implements HasUniqueIdentifier, 
                              Sublistable<Grandchild>, 
                              Combinable<Child> 
{   List<Grandchild> sublist; ...  }

public class Grandchild implements HasUniqueIdentifier, 
                                   Combinable<Grandchild> 
{    }

次のような一般的なメソッドが必要です。

public <V, T extends HasUniqueIdentifier & Combinable<T> & Sublistable<V>> 
List<T> combine(List<T> items) {
    Multimap<String, T> similarItemMap = HashMultimap.create();
    for (T item: items) {
        similarItemMap.put(item.getUniqueIdentifier(), item);
    }

    List<T> output = new ArrayList<T>();
    for (Collection<T> similarCollection : similarItemMap.asMap().values()) {
        List<T> similarItems = Lists.newArrayList(similarCollection);
        T source = similarItems.get(0);
        for (int i = 0; i < similarItems.size(); i++) {
            source = source.add(similarItems.get(i));
        }
        output.add(source);
    }

    for (T item : output) {
        if (item.hasSublist()) {
            item.setSublist(combine(item.getSublist));
        }
    }
    return output;
}

これが無限ループを作成する可能性があることを認識し(最下位クラス--Grandchild --がSublistableとsethasSublist() { return false; }などを実装していない限り)、このメソッドがジェネリックスに夢中になっているという事実と同様に、私は尋ねなければなりません:いくつかありますかこの方法でメソッドを呼び出すことができるように、これを少し書き直すことができます。

combine(listOfGrandparents)

または、これが1つの方法であることをあきらめて、より良い方法でリファクタリングを試みる必要がありますか?


編集: 私がやろうとしていることをよりよく説明するために、タイプのオブジェクトのリストがありますA。各オブジェクトaには、タイプのオブジェクトのリストがありますB。各オブジェクトbには、タイプなどのオブジェクトのリストがありC、最終的にタイプT(さまざまなレベルのT)にサブリストがなくなるまで続きます。

各タイプには、基本的に、「マージ」または「結合」メソッドに対して実行する必要がある3つのことがあります。

  1. item.getUniqueIdentifier()メソッドを使用して、すべての「いいね」アイテムをコンテナに収集します
  2. source.add(other)方法を使用して、すべての同様のアイテムを1つのアイテムに結合します
  3. アイテムにサブリストがある場合は、サブリストでマージを実行します。

n各アイテムの動作は非常に似ているので、タイプごとに1つずつメソッドを用意する代わりに、1つのメソッドを使用できると便利です。残念ながら、(上記の特定のインターフェースの一部またはすべてを実装したことを除いて)どのタイプも同じであることが保証されていないため、ジェネリックメソッドを作成することは困難です。私が見逃しているこれを行う方法はありますか?


編集2: 私はその種の仕事をする方法を見つけました。基本的に、これに変更されます。

public <V extends HasUniqueIdentifier & Combinable<V>, 
        T extends HasUniqueIdentifier & Combinable<T>> 
List<T> combine(List<T> items) {
    Multimap<String, T> similarItemMap = HashMultimap.create();
    for (T item: items) {
        similarItemMap.put(item.getUniqueIdentifier(), item);
    }

    List<T> output = new ArrayList<T>();
    for (Collection<T> similarCollection : similarItemMap.asMap().values()) {
        List<T> similarItems = Lists.newArrayList(similarCollection);
        T source = similarItems.get(0);
        for (int i = 0; i < similarItems.size(); i++) {
            source = source.add(similarItems.get(i));
        }
        output.add(source);
    }

    for (T item : output) {
        if (item instanceof Sublistable<?>) {
            @SuppressWarnings("unchecked")
            Sublistable<V> sublistableItem = ((Sublistable<V>)sublistableItem);
            if (sublistableItem.hasSublist()) {
                sublistableItem.setSublist(combine(sublistableItem.getSublist));
            }
        }
    }
    return output;
}

残念ながら、この方法ではa@SupressWarningsとaの両方が必要instanceofですが、可能であれば避けたいと思います。しかし、私はまだ何も見つけていません。

4

1 に答える 1

1

空虚なことを考えると、最初の解決策は問題ありGrandChild implements Sublistable<Void>ません。ツリーはより均一で、再帰的に扱いやすくなっています。1つをマージすることもできますinterface Node<T,V> extends HasUniqueIdentifier, Combinable<T>, Sublistable<V>{}

したくない場合はGrandChild implements Sublistable、2番目のソリューションでも問題ありません。instanceofマーカー インターフェイスをテストするためのシングルは罪ではありません。コードは次のように書き換えることができます

public <T extends HasUniqueIdentifier & Combinable<T>> 
List<T> combine(List<T> items) 
{
    ...
    List<T> output = new ArrayList<T>();
    ...

    for (T item : output) {
        if (item instanceof Sublistable<?>) 
            combineSublist((Sublistable<?>)item);

    return output;
}

private <V> void combineSublist(Sublistable<V> sublistableItem)
{
    if (sublistableItem.hasSublist()) {
        sublistableItem.setSublist(combine(sublistableItem.getSublist));
}
于 2013-03-06T15:44:23.610 に答える