2008-11-06 3 views
8

Я реализую класс для сравнения деревьев каталогов (в C#). Сначала я реализовал фактическое сравнение в конструкторе класса. Примерно так:Считается плохим дизайном делать длительные операции в конструкторе?

DirectoryComparer c = new DirectoryComparer("C:\\Dir1", "C:\\Dir2"); 

Но это не кажется «правильным» сделать возможную длительную операцию в конструкторе. Альтернативный способ состоит в том, чтобы сделать конструктор частным и добавить статический метод следующим образом:

DirectoryComparer c = DirectoryComparer.Compare("C:\\Dir1", "C:\\Dir2"); 

Как вы думаете? Вы ожидаете, что конструктор будет «быстрым»? Является ли второй пример лучше или это просто усложняет использование класса?

КСТАТИ:

Я не буду отмечать какой-либо ответ, как принято, потому что я не думаю, что это правильный ответ, просто предпочтения и вкус.

Edit:

Просто чтобы прояснить мой пример немного. Я не только заинтересован, если каталоги отличаются, но я также заинтересован в том, как они отличаются (какие файлы). Таким образом, простого значения возврата int не будет достаточно. Ответ cdragon76.myopenid.com на самом деле довольно близок к тому, что я хочу (+1 к вам).

+1

Если вы не отметите ответ, возможно, это должна быть вики сообщества? – 2009-03-13 07:48:04

+0

Я согласен [10chars] – 2009-03-13 07:51:28

ответ

10

Я предпочитаю второй.

Я ожидаю, что конструктор будет препятствовать классу. Метод сравнения делает то, что он предназначен.

3

Вы никогда не должны делать ничего, что может привести к ошибке в конструкторе. Вы не хотите создавать недопустимые объекты. Хотя вы можете реализовать «зомбическое» состояние, в котором объект не делает многого, гораздо лучше выполнить любую сложную логику в отдельных методах.

+0

Совершенно нормально, если конструктор терпит неудачу и выбросит исключение. В этой области есть много примеров этого. Он должен убедиться, что он не теряет ссылки на себя во время конструктора, но, кроме того, это нормально. Не то чтобы мне нравились сложные конструкторы, заметьте. – 2008-11-06 20:06:15

2

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

Вы также можете сделать это немного проще, разрешив конструктору передать два пути, а затем метод Compare(), который фактически выполняет обработку.

5

Я думаю, что интерфейс может быть тем, что вам нужно. Я бы создал класс для представления каталога и реализовал интерфейс DirectoryComparer. Этот интерфейс будет включать метод сравнения. Если у C# уже есть интерфейс Comparable, вы также можете просто реализовать это.

В коде, ваш звонок будет:

D1 = new Directory("C:\"); 
.. 
D1.compare(D2); 
1

Мне нравится второй пример, потому что он объясняет, что именно происходит, когда вы экземпляр объекта. Кроме того, я всегда использую конструктор для инициализации всех глобальных настроек класса.

12

Я бы подумал, что сочетание двух является «правильным» выбором, так как я ожидаю, что метод Compare вернет результат сравнения, а не сам сравнитель.

DirectoryComparer c = new DirectoryComparer(); 

int equality = c.Compare("C:\\Dir1", "C:\\Dir2"); 

... и, как отмечает Дана, есть IComparer интерфейс в .NET, который отражает эту картину.

Метод IComparer.Compare возвращает значение int, поскольку использование классов IComparer в первую очередь относится к сортировке. Общий характер, хотя подходит проблему вопроса в том, что:

  1. Конструктор инициализирует экземпляр с (по выбору) «настройки» параметров
  2. СРАВНИТЬ метод принимает два параметра «данные», сравнивает их и возвращает результат в» "

Теперь результатом может быть int, bool, коллекция различий. Что бы ни требовалось.

1

Я думаю, что для общего назначения компаратора вы можете на строительстве только хотите указать файлы, которые вы сравниваете, а затем сравнить later- таким образом, вы также можете реализовать расширенную логику:

  • Compare снова-, что если изменились каталоги?
  • Измените файлы, которые вы сравниваете, обновив элементы.

Кроме того, вы можете рассмотреть в своей реализации получение сообщений от вашей ОС, когда файлы были изменены в целевых каталогах, и, при необходимости, повторно переделать.

Дело в том, что вы накладываете ограничения, полагая, что этот класс будет использоваться только один раз для одного экземпляра этих файлов.

Поэтому я предпочитаю:

DirectoryComparer = new DirectoryComparer(&Dir1,&Dir2);

DirectoryComparer->Compare();

Или

DirectoryComparer = new DirectoryComparer();

DirectoryComparer->Compare(&Dir1,&Dir2);

0

Если вы работаете с C#, вы можете использовать методы расширения для создания методы для сравнения 2 каталогов, которые вы будет прикрепляться к сборке в DirectoryClass, поэтому он выглядел бы как-то вроде:

Directory dir1 = new Directory("C:\....."); 
Directory dir2 = new Directory("D:\....."); 

DirectoryCompare c = dir1.CompareTo(dir2); 

Это было бы намного более четкое воплощение. Подробнее о методах расширения here.

0

Если операция может занять неизвестное время, это операция, которую вы можете экспортировать в другой поток (поэтому ваш основной поток не будет блокировать и может выполнять другие функции, например, показывать индикатор хода вращения для пример). Другие приложения, возможно, не захотят этого делать, они могут хотеть все в пределах одного потока (например, те, у которых нет интерфейса). Перемещение объекта в отдельный поток немного неудобно ИМХО. Я бы предпочел создать объект (быстро) в моем текущем потоке, а затем просто позволить методу его запускать в другом потоке, и как только метод закончен, другой поток может умереть, и я могу схватить результат этого метода в моем текущий поток, используя другой метод объекта перед тем, как сбрасывать объект, так как я счастлив, как только я знаю результат (или сохраняю копию, если результат включает в себя больше деталей, которые, возможно, придется потреблять по одному).

3

Я согласен с общим чувством не выполнения длительных операций внутри конструкторов.

Кроме того, хотя по вопросу о дизайне я бы рассмотрел возможность изменения вашего второго примера, чтобы метод DirectoryComparer.Compare возвращал нечто, отличное от объекта DirectoryComparer. (Возможно, новый класс называется DirectoryDifferences или DirectoryComparisonResult.) Объект типа DirectoryComparer звучит как объект, который вы использовали бы для сравнения каталогов, в отличие от объекта, представляющего различия между парой каталогов.

Затем, если вы хотите определить различные способы сравнения каталогов (например, игнорировать временные метки, атрибуты readonly, пустые каталоги и т. Д.), Вы можете передать эти параметры в конструктор класса DirectoryComparer. Или, если вы всегда хотите, чтобы DirectoryComparer имел точные правила сравнения каталогов, вы можете просто сделать DirectoryComparer статическим классом.

Например:

DirectoryComparer comparer = new DirectoryComparer(
    DirectoryComparerOptions.IgnoreDirectoryAttributes 
); 
DirectoryComparerResult result = comparer.Compare("C:\\Dir1", "C:\\Dir2"); 
0

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

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

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

Обычно я стараюсь делать такие вещи: Не сохраняйте состояние в экземпляре, если оно может быть передано в качестве аргументов в методы службы. Попробуйте создать объект с неизменным состоянием. Определение атрибутов, подобных тем, которые используются в equals и hashcode, должно всегда быть неизменным.

Концептуальный конструктор - это функция, отображающая представление объекта в объект, который он представляет.

По определению выше Integer.valueOf (1) на самом деле больше конструктора, чем новое Integer (1), потому что Integer.valueOf (1) == Integer.valueOf (1). , В любом случае это понятие также означает, что все аргументы cosntructor и только аргумент конструктора должны определять поведение тела равным образом.

0

Я бы определенно сделал второй.

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

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

0

Я не думаю, что разговор об абстрактных терминах, таких как «длительный», имеет какое-либо отношение к решению, если вы помещаете что-то в конструктор или нет.

Конструктор - это то, что должно использоваться для инициализации объекта, метод должен использоваться для «делать что-то», т. Е. Иметь функцию.

1

Я думаю, что конструктор не только занимает столько времени, сколько необходимо для построения допустимого объекта, но для этого требуется конструктор. Отсрочить создание объекта очень плохо, поскольку вы в конечном итоге с потенциально недействительными объектами. Таким образом, вам нужно будет проверять объект каждый раз, прежде чем прикоснуться к нему (так оно и делается в MFC, у вас есть методы bool IsValid()).

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

Что делает класс DirectoryComparer? В чем это ответственность? С моей точки зрения (который является представлением программиста на C++), похоже, вам будет лучше с помощью бесплатной функции, но я не думаю, что вы можете иметь бесплатные функции на C#, не так ли? Думаю, вы соберете файлы, которые отличаются в объекте DirectoryComparer. Если это так, вы можете создать нечто вроде массива файлов или эквивалентного класса, названного соответствующим образом.

Смежные вопросы