1

これは、コードの単純さとパフォーマンスに関係する設計上の問題です。

特定のユーザー ID の一連の値が 2 つのシステム間で同じであることを確認したいとします。ここでの例は、学生 ID がシステム A とシステム B で同じ数のコース登録を持っていることを確認することです。

このために、以下を作成します。

List<String> studentList = new ArrayList<String>();
Set<String> sysAEnrollments = new HashSet<String>();
Set<String> sysBEnrollments = new HashSet<String>();
private Map<String, String> badEnrollList = new HashMap<String, String>();

学生 ID のリスト (studentList) を指定して、適切に入力します。

studentList = getCurrentStudentList();

for (String id : studentList){
   sysAEnrollments = getSysAEnrollments(id);
   sysBEnrollments = getSysBEnrollments(id);
   if (!sysAEnrollments.containsAll(sysBEnrollments)){
      badEnrollList.put(id, getBadEnrollmentsById(id, sysAEnrollments, sysBEnrollments));
   }
}

質問:メソッド「getBadEnrollmentsById」は何を返す必要がありますか?

単に印刷できるように、十分な意味を持つ連結された文字列のいずれかです。または、新しいオブジェクトを用意します。たとえば、コース ID のリストを持つ別のコレクションを作成します。このコレクションは、さらなる処理には使用できますが、印刷出力には使用するのが難しくなります。

明確さとパフォーマンスのために、予想されるすべてのオブジェクトを徹底的に設計するか、それらの一部を連結された文字列に置き換える価値がありますか?

ノート:

  • システム A は信頼できるソースとして優先されます
  • getBadEnrollmentsByIdからの出力には、すべてのコースが含まれている必要があり、システム B で不足しているコースにフラグを立てる必要があります。

提案された解決策: (2012-SEP-14)

編集 (2012-SEP-17): Course クラスを更新して、hashCode と equals を含めました

user351721 が提案したように、期待される結果/要件に一致する残りのオブジェクトのモデリングを続けました。わずかな変更が大きな違いをもたらし、この設計上の欠陥を調べて実装を完了することができました。

改訂されたコレクションは次のとおりです。

List<String> studentList = new ArrayList<String>();
Enrollment sysAEnrollments;
Enrollment sysBEnrollments;
Map<String, List<String>> badEnrollList = new HashMap<String, List<String>>();

そして、登録を入力します。

for (String id : studentList){
    sysAEnrollments = getSysAEnrollments(id);
    sysBEnrollments = getSysBEnrollments(id);
    if (!sysAEnrollments.getCourses().containsAll(sysBEnrollments.getCourses())){
        List<String> missingCourses = getProblemEnrollmentListById(id, sysAEnrollments, sysBEnrollments);
        badEnrollList.put(id, missingCourses);
    }
}

したがって、今のところ出力は、各 ArrayList を取得してコース名を出力することにより、badEnrollList から出力できます。* の付いたコース名は、sysB にないことを意味します。

登録クラスは次のようになります。

public class Enrollment {
    private Set<Course> courses = new HashSet<Course>();
    public void setCourses(Set<Course> courses){
        this.courses = courses;
    }
    public Set<Course> getCourses(){
        return this.courses;
    }
}

Course クラスは次のようになりました。

public class Course {
    private String id;
    private String name;

    public String getId() {
        return id;
    }
    public void setId(final String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(final String name) {
        this.name = name;
    }

    // Must override hashCode() and equals()
    @Override
    public boolean equals(Object o){
        if (o == this)
            return true;
        if (!(o instanceof Course))
            return false;
        Course c = (Course) o;
        return c.id.equals(this.id) && c.name.equals(this.name);
    }

    @Override 
    public int hashCode(){
        // Magic numbers as shown on Joshua Bloch's book "Effective Java" 2nd Edition, p.48
        int result = 17;
        result = 31 * this.id.hashCode();
        result = 31 * this.name.hashCode();
        return result;
    }   
}

変更は微妙に見えるかもしれませんが、重要な手掛かりは、登録は文字列のコレクションではなく、登録はコースのコレクションであり、各コースには名前と可用性プロパティがあることです。それらは多くのことをしていないように見えますが、それらを使用することで、使用しているオブジェクトを定義し、これらのクラスを将来どのように再利用できるかを文書化しています。

4

4 に答える 4

1

「Growing Object-Oriented Software, Guided by Tests」では、この質問に対処しています: 第 7 章「値の型」。読む価値があります。抜粋:

コードを書けば書くほど、型を定義してドメイン内の値の概念を表す必要があると確信するようになります。より自明な一貫したドメイン モデルを作成するのに役立ちます。たとえば、システムで Item タイプを作成する場合、String を使用するだけでなく、メソッド呼び出しを追跡することなく、変更に関連するすべてのコードを見つけることができます。

于 2012-09-14T01:46:16.493 に答える
1

連結文字列

パターンと対応する有効な文字列のセットを定義し、検証とエンティティ クラスへの変換を実装する必要があることを意味します。インターフェイスまたはクラスを提供すると、アプリケーションで作業する可能性のある他のプログラマーは言うまでもなく、約 1 年でコードを簡単に更新できるようになります。学生、登録、またはコース オブジェクトを に保存してみませんbadEnrollListか? これらのオブジェクトはどのように見え、それらをどうしたいですか?

一般的に: はい、期待されるすべてのオブジェクトを徹底的に設計する価値があります。

于 2012-09-13T22:47:05.340 に答える
1

List<String>などのコレクションが望ましい戻り値になると思います。これにより、2 つのセット間の複数の不一致をより効率的に把握し、2 番目のオブジェクトで不足しているコースをより直感的に処理できます。情報をどのように伝えたいかにもよりますが、リストを印刷することもそれほど難しくありません。

のメソッドは、2 つのセット間の等価性を確保するためのよりクリーンで直感的な.equals()方法であることも言及する価値があります。Set

于 2012-09-13T23:10:53.350 に答える
0

これらすべてのセットとマップを使用する代わりに、問題の実際のビジネス オブジェクトを反映する Plain Old Java Objects (POJO) を使用します。あなたが示したことから、ある種のIDを持ち、システムAとシステムBのクラスに登録されている学生がいます。次のように定義された学生オブジェクトのセットを構築します。

public class Student {
    private String id;
    private List<String> enrollmentsA;
    private List<String> enrollmentsB;

    // appropriate getters and setters
}

クラスで何か他のことをしたいかどうかによっては、それを表す何らかの形の EnrolledClass オブジェクトを作成する方が望ましい場合もあります。

次に、学生クラス内で、「悪い」登録を決定するメソッドを作成します。このデータを使って電子メール メッセージを生成するだけであれば、文字列のように単純なものでもかまいません。

public String getBadEnrollmentsMessage() {
    List<String> enrolledBoth = getCommonEnrollments();
    List<String> enrolledOnlyA = getAOnlyEnrollments();
    List<String> enrolledOnlyB = getBOnlyEnrollments();

    StringBuilder output;
    // format the contents of the above lists into output
    // format should be however you want it in the email.

    return output.toString();
}

次に、登録メッセージを電子メールで送信する学生のマップを作成できます。

HashMap<Student, String> studentEmails;

for (Student s : allStudents) {
    studentEmails.put(s, s.getBadEnrollmentsMessage());
}

もちろん、 のようなメソッドがある場合、getBadEnrollmentsMessage()そもそも学生と文字列のマップが必要かどうかさえわかりません。率直に言って、sendEnrollmentEmailメソッドを作成して を渡し、そこStudentからメッセージを抽出するだけgetBadEnrollmentsMessage()です。

于 2012-09-14T01:23:14.540 に答える