web-dev-qa-db-ja.com

メソッドには、コレクションの具体的な実装が必要です。具体的な実装を返すために、すべてのアップストリームメソッドを変更する必要がありますか?

Mapを処理するメソッドprocessDataAssumingLinkedHashMapInput()があります。 Mapは、値順に並べられたLinkedHashMapである必要があります。データはgetStrIntMap(query)から取得されます。このメソッドはSQLからresultSetを取得し、それをLinkedHashMapに配置します。コードは次のとおりです。

_public void processDataAssumingLinkedHashMapInput(){
    String query = "select MYID, MYVALUE from MYTABLE order by MYVALUE";
    Map<String, Integer> map = SQLTools.getStrIntMap(query);

    for (Map.Entry<String, Integer> entry : rawEntryToSortOrderMap.entrySet()) {
        //do something, assuming that values are ordered
    }
    //do more stuff
}

//SQLTools method, used by multiple other classes
public static Map<String, Integer> getStrIntMap(String query){
    Map<String, Integer> map = new LinkedHashMap<>();
    //ResultSet to map 
    return map;
}
_

私の懸念は、誰かがgetStrIntMap(String query)Map<String, Integer> map = new HashMap<>();に変更することを決定した場合(たとえばパフォーマンス上の理由で)、processDataAssumingLinkedHashMapInput()が壊れることです。 getStrIntMapの戻り値の型を具体的な実装に変更することはできますが、見栄えが悪く、誰かが抽象Mapに戻すことになります。 1つはMapを返し、もう1つはLinkedHashMapを返す、2つの本質的に同一のメソッドを作成できますが、これはDRYの原則に違反します。 processDataAssumingLinkedHashMapInputメソッドの始まりですが、これもDRYルールに違反しています。この場合のベストプラクティスは何ですか?

1
Stepan

少しIoCを使用します。呼び出し元がマップインスタンスを挿入できるようにリファクタリングします。これにより、他の開発者がより効率的なマップを使用できるようになり、必要な機能でマップを使用できるようになります。

public static void fillStrIntMap(String query, Map<String, Integer> map){
    //ResultSet to map 
}
0
John Wu

提供されたMapから呼び出し元が提供した空のqueryを設定するメソッドをライブラリに追加することをお勧めします。

物事を乾いた状態に保つと、getStrIntMapメソッドはこの他のメソッドを呼び出し、新しいLinkedHashMapを渡し、そのMapを返します(インターフェイスとして、その署名は変更されません)。

次に、呼び出し元は、疎結合用のgetStrIntMapインターフェイスを返す標準のMapを選択できます。または、呼び出し元は、選択したMapを渡す他のパスを選択できます。マップが実際にLinkedHashMapであることが明確に保証されていますが、ライブラリAPIが具象型を公開する必要はありません。

4
Erik Eidt

1つの可能性は、抽象マップを拡張してそれを返すOrderedMapと呼ばれる新しい抽象型を作成することです。そうすれば、メソッドは引き続き抽象化を返しますが、順序付けられたマップタイプを返すように強制されます。既存の呼び出し元は、必要に応じて、返されたオブジェクトを基本マップとして扱うことができます。または、HashMapなどの戻り値に変更されないように実装が保護された状態で、返されたオブジェクトが順序付けられていることを確信できます。

2
Weyland Yutani