2017-03-03 15 views
-1

私と私の同僚の1は、次のような問題を解決しようとしていた。これはアンチパターンの例ですか?

は、私の同僚の 一つは、特定の一つから一つの特性をフェッチA. から一つの特定のプロパティを抽出する問題に直面していたクラスの例を取ることができますクラス(この場合はA)は簡単です。 には複数のクラス(A1、A2 ...)があると仮定し、これらのクラスのコレクションから特定のプロパティーを1つずつ取り出して、コードの再利用性を高めたいとします。

List<String> tempList = new ArrayList<>(); 
for(A a : listOfAInstances) { 
    tempList.add(a.getName()); 
} 
return tempList; 

を今、私は各クラスと異なる性質のためにこれをしなければならない複数のクラスが存在する場合:

例えば

public class A { 
    private String name; 
    . 
    . 
    . 
} 
List<String> listOfNames = createNameList(listOfAInstances); 

createNameList()メソッドは、次のようになります。

  1. リフレクションベースのアプローチ:

    は、私は2つのアプローチを提案しました。
  2. "PropertyExtractable"というインターフェイスを作成し、そこにメソッド "extractProperty"を配置します。

以下に示すよう:このため

interface PropertyExtractable { 
    Object extractProperty(); 
} 

public class A implements PropertyExtractable { 
    private String name; 
    . 
    . 
    . 
    public Object extractProperty() { 
     return this.name; 
    } 
} 

を私はその後、すなわちどこでも使用することができ、いくつかのユーティリティメソッドを書くことができます

public Object getPropertiesOfPropertyExtractable(PropertyExtractable prExtractable) { 
     return prExtractable.extractProperty(); 
    } 

これが背景だった、私の一つの他の同僚が持っていました2番目のアプローチについての別の意見は、彼はそれがアンチパターンのようだと私に言った。彼は私に説明しようとしましたが、私はそれを完全には得られなかったので、私はここで尋ねています。

この例をJavaのComparatorインターフェイスと比較しようとしています。 javaのように私たちはカスタムオブジェクトクラスのいずれかでComparatorを使用することができ、比較のロジックを定義することができます。なぜ抽出ロジックを定義できないのですか?

さらに多くのインターフェイスをこの方法で使用できます。私たちはそれを使用しないでください

私はこのアプローチがアンチパターンであることを知りたいですか?どうして?

+1

私の最初の考えは、タイプセーフではないということでした。次に、異なるクラスのリストを持つことができれば、すでにそれらの共通インターフェースを持つ必要があります。そこに 'String getName()'を含めてみませんか? – Fildor

+1

サンプルコードと "例えば"テキストがクラス名と一致すると、多くの手助けをします。 –

+1

オーバーライドされたメソッドでより具体的な戻り値の型を使用できることを忘れないでください: 'A'の' public String extractProperty() '。それで 'A'への参照があれば、' String name = myA.extractProperty(); 'と書くことができます。これはキャストする必要はありません。 –

答えて

0

あなたは別の方法で抽出するコードを配置し、それを再利用することができます

class A { 
    private String name; 

    public String getName() { 
     return name; 
    } 
} 

class B { 
    private String surname; 

    public String getSurname() { 
     return surname; 
    } 
} 

public class SomeClass { 

    private <T> List<String> extractFields(List<T> list, Function<T, String> extractorFunction) { 
     return list.stream().map(extractorFunction).collect(Collectors.toList()); 
    } 

    public void someMethod() { 

     List<A> listOfInstancesA = new ArrayList<>(); 
     List<B> listOfInstancesB = new ArrayList<>(); 

     // fill lists 

     List<String> fieldsA = extractFields(listOfInstancesA, A::getName); 
     List<String> fieldsB = extractFields(listOfInstancesB, B::getSurname); 
    } 
} 
+0

私はこの質問を投稿した理由は、問題の解決策を見つけることではなく、正しい解決方法を見つけることです。私が言及したように私はすでにこれについて定義された2つのアプローチを持っています。私はどちらかを選ぶことができます、私はそれを確信しています。 –

+0

私の提案は、インターフェイスの作成と反映ではないので、私はこれをお勧めしました。初期のクラスAとBには触れません。 –

+0

この新しいアプローチに感謝します:)しかし、私はもっと一般的な問題としてそれを見ています。私はそれを少し知っているのでここでJavaを使用しましたが、同じことがSwift/JavaScriptまたはその他の言語。 –

0

あなたが記述状況は変更したくないレガシーシステムと協力しています。

共通のプロパティ(Comparatorインターフェイスの例のような)のインターフェイスを導入しない場合は、あなたは実際に機能的なインターフェースが必要なので、アンチパターンであるかもしれない意味のないインターフェースを導入しました:PropertyExtractableとNamedObject =>はメソッドを持っています:String getName())。

Reflectionを実装する場合は、インターフェースは正しいかもしれませんが、表示されません(例:あなたの場合はすでにの反射がJavaに組み込まれています。

通常、アダプタパターンを使用して、要求されたインターフェイスを実装していないオブジェクトからプロパティ/メソッドを取得します。

+0

私はこの部分を理解しませんでした。「あなたは意味のないインターフェースを導入しました」このような場合に、私が探すべき正確な「意味」は何ですか? –

+0

あなたは、そのようなインターフェースの使用が普遍的な抽象レベルに移行しました。これは私が、リフレクションがコードの実際の構造(オブジェクト、クラス、プロパティなど)に作用するので、あなたがリフレクションのためのメソッドを作成しようとしているなら、ユースケースの意味です。しかし、ユースケースは、具体的なドメインに由来する具体的な(名前付きのオブジェクト)です。ドメインの共通のプロパティと、そこからインターフェイスを導出できるかどうかを調べる必要があります(私の例はNamedObjectインターフェイスでした)。 – PsiX

+0

私のプロパティは一般的ではありません(共通インタフェースには移動できません)。しかし、呼び出されたときに特定のプロパティ(既に決定されている)を返すことができるすべてのクラスで共通の動作が必要な場合は、私の同僚の一人はSwiftに8から10のクラスを持っているので、画面に表示する特定のプロパティを抽出したい(ドロップダウンの可能性があります)。だから私が言ったように、2つのアプローチ、リフレクション/インターフェイスの使用は、すべての実装がプロパティを取得するこの動作を使用するようにすることができます。 –

関連する問題