3

A と B の 2 つの csv ファイルがあります。A はマスター リポジトリです。これらのファイルを読み取り、B のレコードを A にマップし、マップされたレコードを別のファイルに保存する必要があります。レコードを保持するクラスは、たとえば Record です。一致したレコードを保持するクラスは、たとえば RecordMatch です。

class Record
{
  string Id;
  string Name;
  string Address;
  string City;
  string State;
  string Zipcode;
}

class RecordMatch
{
  string Aid;
  string AName;
  string Bid;
  string BName;
  double NameMatchPercent;
}

マッピング シナリオは次のようになります。まず、B の各レコードに対して、A のレコードが州、都市、郵便番号を使用してフィルター処理されます。このようにフィルタリングされた A のレコードは、次に B のレコードと比較されます。この比較は、名前フィールド間のものであり、ファジー文字列アルゴリズムを使用した最適一致比較です。最適な一致が選択され、保存されます。

文字列マッチング アルゴリズムにより、一致率が示されます。したがって、すべての試合から最高の結果を選択する必要があります。

シナリオを説明するために最善を尽くしたので、設計の問題に移ります。私の最初の設計は、次のような Mapper クラスを作成することでした。

class Mapper
{
  List<Record> ReadFromFile(File);
  List<Record> FilterData(FilterType);
  void Save(List<Record>);
  RecordMatch MatchRecord(Record A, Record B);
}

しかし、デザインを見ると、単にいくつかのメソッドに対するクラス ラッパーのように見えます。OO のデザインは見当たりません。また、Match() は Mapper クラスよりも Record クラスに属していると感じました。

しかし、別の見方をすると、このクラスはリポジトリ パターンに似たものを実装しているように見えました。

私が考える別の方法は、Mapper クラスを保持し、Match() メソッドを Record クラスに移動することです。次のようになります。

class Mapper
{
  List<Record> ReadFromFile(File);
  List<Record> FilterData(FilterType);
  void Save(List<Record>);
}

class Record
{
  string id;
  string name;
  string address;
  // other fields;

  public RecordMatch Match (Record record)
  {
    // This record will compare the name field with that of the passed Record.
    // It will return RecordMatch specifyin the percent of match.
  }
}

今、私はこの単純なシナリオで完全に混乱しています。このシナリオで理想的な OO 設計とはどのようなものでしょうか?

4

2 に答える 2

4

面白いことに、私は現在、これとほとんど同じようなプロジェクトに取り組んでいます。

簡単な答え:まず最初に、メソッドがしばらく間違ったクラスにあったとしても、それは世界の終わりではありません! すべてのクラスがテストでカバーされている場合関数が存在する場所は重要ですが、ドメインの王であるあなたが適切と考えるように流動的に変更できます。

これをテストしていない場合は、それが私の最初の提案です。私よりも多くの賢明な人々が、TDD とテストがクラスを最適な設計に自然に導くのにどのように役立つかについて述べています。

より長い回答:設計に適用するパターンを探すよりも、次のように考えるのが好きです: 各クラスを変更する必要がある理由は何ですか? これらの理由を互いに切り離すと (これは TDD でできることの 1 つです)、コードからデザイン パターンが自然に浮かび上がってくるのがわかります。

あなたの質問を読んでいくつかのパスで私が考えることができる変更するいくつかの理由を次に示します。

  1. データ ファイルの形式が変更される/列が追加される
  2. より適切なマッチング アルゴリズムを見つけた場合、または「今度は携帯電話番号もフィルタリングしたい」
  3. xml/yaml/etc ファイルにも一致させるように求められます
  4. 新しい形式/場所で保存するように求められます

これらのいずれかを実装するために「if ステートメント」をどこかに追加する必要がある場合、それはおそらく、共通のインターフェイスを実装するサブクラスの継ぎ目です。

また、作成したファイルを新しい場所に保存したいとします。これは変更する理由の 1 つであり、マージ戦略を変更する必要があることと重なってはなりません。これら 2 つの部分が同じクラスにある場合、そのクラスには 2 つの責任があり、単一責任の原則に違反しています。

これは非常に簡単な例です。優れた OO 設計についてさらに詳しく知るには、SOLID の原則を確認してください。これらを学び、OO 設計全体に慎重に適用することをお勧めします。

于 2011-09-14T13:58:10.727 に答える
1

これを試してみました。おそらく、MatchingAlgorithm (および必要に応じて Strategy と Template) の構成を使用することを除いて、OO の原則または設計パターンに関してできることはあまりないと思います。これが私が調理したものです:

    class Mapper {
        map(String fileA, String fileB, String fileC) {
            RecordsList a = new RecordsList(fileA);
            RecordsList b = new RecordsList(fileB);
            MatchingRecordsList c = new MatchingRecordsList();

            for(Record rb : b) {
                int highestPerc = -1;
                MatchingRecords matchingRec;

                for(Record ra : a) {
                    int perc;
                    rb.setMatchingAlgorithm(someAlgorithmYouVeDefined);
                    perc = rb.match(ra);
                    if(perc > highestPerc) {
                        matchingRec = new MatchingRecords(rb, ra, perc);
                    }
                }

                if(matchingRec != null) {
                    c.add(matchingRec);
                }
            }

            c.saveToFile(fileC);
        }
    }

    class MatchingAlgorithm {
        int match(Record b, Record a) {
            int result;
            // do your magic
            return result;
        }
    }

    class Record {
        String Id;
        String Name;
        String Address;
        String City;
        String State;
        String Zipcode;

        MatchingAlgorithm alg;

        setMatchingAlgorithm(MatchingAlgorithm alg) {
            this.alg = alg;
        }

        int match(Record r) {
            int result; -- perc of match
            // do the matching by making use of the algorithm
            result = alg.match(this, r);
            return result;
        }

    }

    class RecordsList implements List<Record> {
        RecordsList(file f) {
            //create list by reading from csv-file)
        }
    }

    class MatchingRecords {
        Record a;
        Record b;
        int matchingPerc;

        MatchingRecords(Record a, Record b, int perc) {
            this.a = a;
            this.b = b;
            this.matchingPerc = perc;
        }
    }

    class MatchingRecordsList {
        add(MatchingRecords mr) {
            //add
        }

        saveToFile(file x) {
            //save to file
        }
    }

(これは Notepad++ で書かれているため、タイプミスなどがある可能性があります。また、提案されたクラスは、もう少しリファクタリングすることで確実に恩恵を受けることができますが、このレイアウトを使用することを選択した場合は、それをお任せします。)

于 2011-09-14T13:42:13.577 に答える