2017-06-18 10 views
2

私は様々なプロパティを持つクラスを持っており、より簡単にそれらの周りをループするためにそれらの周りにラッパーメソッドを記述したいと思います。メソッドは、コレクションまたは単一の値を返します

一部のプロパティは、のコレクションの値を返します。単一のの値を返します。そして、私はこれに最善のアプローチを探しています。

私の最初のアプローチは、getterが返すプロパティをラッパーメソッドが返すようにすることです。

public class Test { 

    public Object getValue(String propName) { 
     if ("attr1".equals(propName)) return getAttribute1(); 
     else if ("attr2".equals(propName)) return getAttribute2(); 
     else return null; 
    } 

    public List<String> getAttribute1() { 
     return Arrays.asList("Hello","World"); 
    } 

    public String getAttribute2() { 
     return "Goodbye"; 
    } 

    public static void main(String[] args) { 

     final Test test=new Test(); 

     Stream.of("attr1","attr2") 
       .forEach(p-> { 
        Object o=test.getValue(p); 
        if (o instanceof Collection) { 
         ((Collection) o).forEach(v->System.out.println(v)); 
        } 
        else { 
         System.out.println(o); 
        } 
       }); 
    } 

} 

このアプローチの悪い点は、呼び出し元が結果がコレクションであるかどうかを自分でテストする必要があることです。

呼び出し側にとってシームレスな他のアプローチは、常にコレクションを返します。ラッパー関数は単一の値をCollectionにラップします。ここではHashSetですが、最小限の1つの要素リストを想定することができます。

public class TestAlt { 

    public Collection getValue(String propName) { 
     if ("attr1".equals(propName)) 
      return getAttribute1(); 
     else if ("attr2".equals(propName)) { 
      Set s = new HashSet(); 
      s.add(getAttribute2()); 
      return s; 
     } 
     else 
      return null; 
    } 

    public List<String> getAttribute1() { 
     return Arrays.asList("Hello", "World"); 
    } 

    public String getAttribute2() { 
     return "Goodbye"; 
    } 

    public static void main(String[] args) { 

     final TestAlt test = new TestAlt(); 

     Stream.of("attr1", "attr2") 
       .forEach(p -> { 
        test.getValue(p).forEach(v -> System.out.println(v)); 
       }); 
    } 

パフォーマンス面では、設計上、...これらのアプローチについてのあなたの意見は?より良いアイデアはありますか?

+0

推測=アイテムが1つしか入っていないコレクションはありますか? – Marichyasana

+0

すべての値を印刷しようとしていますか?他の目的はありませんか?また、型は常に 'List 'と 'String'のいずれかになりますか? 'int'のような他の型もありますか? – Sweeper

+0

@Marichyasana 1つのアイテムだけを持つコレクションは簡単に書き込み可能です – lvr123

答えて

0

まあ、各属性に対して実行されるアクションをオブジェクトに渡して、オブジェクトがそれをどのように扱うかを決めることができます。例えば:クラスのテストで

:あなたが何をしたいのか、ない機能handle(String s)、と

public void forEachAttribute(String propName, Handler h) { 
    if ("attr1".equals(propName)) 
     h.handle(getAttribute1()); 
    else if ("attr2".equals(propName)) { 
     getAttribute2().forEach(o -> h.handle(o)) 
    } 
} 

とクラスHandler

あなたがTestを編集することができない場合は、Test性能面

public void forEachTestAttribute(Test t, String propName, Handler h)... 

外の機能を移動することができます。これは、キャストを削除しますが、作成されます。これは、if節

デザインワイズを削除より多くのクラス。

*編集:それはまたタイプ・セキュリティを維持し、属性(Stringint、など)の複数の種類がある場合、あなたはまだ型セキュリティを維持するために、より多くのhandle -functionsを追加することができます。私はこれにあなたのコードを書き換えることになるデザインについて

+0

これは、 'Handler'の結果を期待していないとうまくいくかもしれません...私はreplace 2' Function'を実行できます:アクションを実行し、結果を出力するもの、 'forEach'の結果を累積するもの1つの値に...そう簡単ではありません。 – lvr123

+0

@ lvr123 'handler.handle()'に何らかの結果を生成させたいのですか?それを行う1つの方法は、すべてをCollectionに追加することです。別の方法は、結果を要求するコードを 'Handler'にも入れることですが、これがあなたのケースで可能かどうかはわかりません。 – Poohl

0

TestAlt.java

import java.util.*; 
import java.util.stream.Stream; 

public class TestAlt { 

    private Map<String, AttributeProcessor> map = AttributeMapFactory.createMap(); 

    public Collection getValue(String propName) { 
     return Optional 
      .ofNullable(map.get(propName)) 
      .map(AttributeProcessor::getAttribute) 
      .orElse(Arrays.asList("default")); //to avoid unexpected NPE's 
    } 


    public static void main(String[] args) { 

     final TestAlt test = new TestAlt(); 

     Stream.of("attr1", "attr2") 
      .forEach(p -> test.getValue(p).forEach(v -> System.out.println(v))); 
    } 
} 

AttributeMapFactory.java

import java.util.HashMap; 
import java.util.Map; 

public class AttributeMapFactory { 

    public static Map<String, AttributeProcessor> createMap() { 
     Map<String, AttributeProcessor> map = new HashMap<>(); 
     map.put("attr1", new HiAttributeProcessor()); 
     map.put("attr2", new ByeAttributeProcessor()); 
     return map; 
    } 
} 

AttributeProcessor.java

import java.util.Collection; 

public interface AttributeProcessor { 

    Collection<String> getAttribute(); 
} 

HiAttributeProcessor。Javaの

import java.util.Arrays; 
import java.util.Collection; 

public class HiAttributeProcessor implements AttributeProcessor{ 

    @Override 
    public Collection<String> getAttribute() { 
     return Arrays.asList("Hello", "World"); 
    } 
} 

ByeAttributeProcessor.java

import java.util.Arrays; 
import java.util.Collection; 

public class ByeAttributeProcessor implements AttributeProcessor{ 

    @Override 
    public Collection<String> getAttribute() { 
     return Arrays.asList("Goodbye"); 
    } 
} 

主なポイントは、あなたがマップとダイナミックディスパッチを使用している場合-else文を取り除くことです。

このアプローチの主な利点は、コードの変更がさらに柔軟になることです。この小さなプログラムの場合、それは本当に重要ではなく、過度のものです。しかし、大企業のアプリケーションについて話しているなら、それは重要です。

+0

これは、私のTestAltのアプローチとほぼ同じアプローチです。ここでは、単一のアイテム属性をCollection(サンプルではArrays.asListを使用したArrayList)にカプセル化しています。残りの部分は、getValueの呼び出しごとにマップと各属性の配列の両方を作成するので、どのようにパフォーマンスが向上するかわかりません。したがって、ループする10の属性がある場合、1マップ+ 10リスト(= 110個のコレクション)を作成するgetValueへの10回の呼び出しを作成しています。私のTestAltは同じ条件で10個のコレクションを作成しますが。 – lvr123

+0

私は設計上の問題ではなく、パフォーマンスに焦点を当てていました。しかし間違いなくあなたは正しいです:余分なコレクションを作成しない方がいいです。 TestAltのクラス変数としてマップを1回だけ初期化することができます。私はそれに応じて私の答えを編集します。私は再び強調したいと思います:あなたのコードベースが絶えず増加している場合は、私の例のデザインがより望ましいでしょう。単体テストをサポートし、新しいコードを補完する方が簡単です。そして、if-elseステートメントの代わりに多態性を使用するので、概念的にはアプローチとは異なります。 –

関連する問題