Объектно-ориентированный дизайн - PullRequest
3 голосов
/ 14 сентября 2011

У меня есть два CSV-файла A и B. 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);
}

Но, глядя на дизайн, он просто выглядит как обертка класса для некоторых методов.Я не вижу никакого дизайна ОО в нем.Я также чувствовал, что Match () больше относится к классу Record, чем к классу Mapper.

Но с другой стороны, я увидел, что класс реализует нечто, похожее на шаблон Repository.

Другой способЯ думаю, что нужно сохранить класс 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.
  }
}

Теперь я полностью запутался в этом простом сценарии.Каким в идеале должен быть хороший ОО-дизайн в этом сценарии?

Ответы [ 2 ]

4 голосов
/ 14 сентября 2011

Довольно забавно, я сейчас работаю над проектом, почти таким же, как этот.

Простой ответ: Хорошо, во-первых, это не конец света, если метод некоторое время находится в неправильном классе!Если у вас все классы покрыты тестами, , где , функции живут, важно, но их можно плавно менять, если вы, король своего домена, сочтете нужным.

Если вы не тестирую это, ну, это было бы моим первым предложением.Многие более умные люди, чем я, отмечали, как TDD и тестирование могут помочь естественным образом привести ваши классы к лучшему дизайну.

Более длинный ответ: Вместо того, чтобы искать шаблоны для применения к дизайну, мне нравится продумывать это так: по каким причинам каждый из ваших классов должен измениться?Если вы отделите эти причины друг от друга (в этом может помочь TDD), то вы начнете видеть, что шаблоны проектирования естественным образом возникают из вашего кода.

Вот несколько причин, по которым я мог бы подумать за несколько проходов, читая ваш вопрос:

  1. Файл данных изменяет формат / добавляет столбцы
  2. Вы найдетелучший алгоритм сопоставления или: «теперь мы хотим выполнить фильтрацию и по номеру мобильного телефона»
  3. Вас также попросят сделать так, чтобы он совпадал с файлами xml / yaml / etc
  4. Вас попросилисохраните его в новом формате / местоположении

Хорошо, поэтому, если реализация любого из них потребует добавления где-то оператора if, возможно, это шов для подклассов, реализующихОбщий интерфейс.

Также предположим, что вы хотите сохранить созданный файл в новом месте.Это одна из причин для изменения, и она не должна пересекаться с необходимостью изменить стратегию слияния.Если эти две части относятся к одному и тому же классу, у этого класса теперь есть две обязанности, и это нарушает принцип единой ответственности .

Итак, это очень краткий пример, чтобы углубиться в подробности с хорошим дизайном ОО, ознакомьтесь с принципами SOLID .Вы не ошибетесь, изучая их и стараясь применять их с осторожностью в своих проектах ОО.

1 голос
/ 14 сентября 2011

Я попробовал.Я думаю, что не так много можно сделать, когда дело доходит до ОО-принципов или шаблонов проектирования, за исключением, возможно, использования композиции для MatchingAlgorithm (и, возможно, стратегии и шаблона, если это необходимо).Вот что я приготовил:

    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 ++, поэтому возможны опечатки и т. Д.; Также предложенные классы, безусловно, могут получить выгоду от небольшого дополнительного рефакторинга, но я оставлю это вамесли вы решите использовать этот макет.)

...