Объектно-ориентированный дизайн

У меня есть два 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.

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

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

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


person Jayesh Bhoot    schedule 14.09.2011    source источник


Ответы (2)


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

person Wivani    schedule 14.09.2011
comment
После публикации этого вопроса я начал мозговой штурм, так как не получил ответа в течение нескольких часов: P. Я придумал дизайн, очень похожий на ваш; вы добавили недостающие части к моим идеям. :) - person Jayesh Bhoot; 15.09.2011
comment
О, и я не собирался набивать это шаблоном проектирования; просто я неправомерно увидел в дизайне что-то похожее на шаблон репозитория (операции чтения, поиска/фильтрации, сохранения, понимаете). Так что я просто упомянул об этом. Но я вижу, что это действительно было то, что я выдумывал; Теперь я собираюсь потратить немного денег на Gang Of Four ;-) - person Jayesh Bhoot; 15.09.2011

Как ни странно, я сейчас работаю над проектом почти таким же, как этот.

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

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

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

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

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

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

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

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

person Steve    schedule 14.09.2011
comment
Я получил приятное облегчение от вашего простого ответа за то, что какое-то время не беспокоился о том, что что-то не так ;-) И да, я тестирую классы; возможно, поэтому у меня возникли сомнения. - person Jayesh Bhoot; 15.09.2011
comment
Я думаю, что это был принцип единой ответственности, который съедал меня. Вы дали хорошее представление о вопросе if. Вещи прояснились в хорошей степени. - person Jayesh Bhoot; 15.09.2011