В любом заданном определении класса я видел определения методов, упорядоченные по-разному: алфавитный, хронологический, основанный на наиболее распространенном использовании, алфавитный, сгруппированный по видимости, алфавитный с геттерами и сеттерами, сгруппированными вместе, и т. Д. Когда я начинаю писать новый класс, Я имею тенденцию просто вводить все, а затем переупорядочивать, когда я закончу писать весь класс. На этой ноте у меня есть три вопроса:
- Имеет ли значение порядок?
- Есть ли «лучший» заказ?
- Я предполагаю, что нет, так каковы плюсы и минусы различных стратегий заказа?
code-quality
Johntron
источник
источник
Ответы:
В некоторых языках программирования порядок имеет значение, потому что вы не можете использовать вещи до тех пор, пока они не будут объявлены. Но, за исключением этого, для большинства языков это не имеет значения для компилятора. Итак, вы остались с этим важно для людей.
Моя любимая цитата Мартина Фаулера такова:
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
так что я бы сказал, что порядок в вашем классе должен зависеть от того, что облегчает людям понимание.Я лично предпочитаю постепенное обращение, которое Боб Мартин дает в своей
Clean Code
книге. Переменные-члены в начале класса, затем конструкторы, а затем все остальные методы. И вы приказываете, чтобы методы были близки к тому, как они используются в классе (вместо того, чтобы произвольно выставлять все общедоступные, а затем закрытые, а затем защищенные). Он называет это минимизацией «вертикального расстояния» или чего-то в этом роде (на данный момент у меня нет книги).Редактировать:
Основная идея «вертикального расстояния» заключается в том, что вы хотите не заставлять людей прыгать вокруг вашего исходного кода просто для того, чтобы понять его. Если вещи связаны, они должны быть ближе друг к другу. Несвязанные вещи могут быть дальше друг от друга.
Глава 5 Чистого кода (отличная книга, кстати) подробно описывает, как мистер Мартин предлагает заказывать код. Он предлагает, чтобы чтение кода работало так же, как чтение газетной статьи: подробности высокого уровня идут первыми (вверху), и вы получаете больше деталей, когда читаете. Он говорит: «Если одна функция вызывает другую, они должны быть расположены вертикально, а вызывающая сторона должна быть выше вызываемой, если это вообще возможно». Кроме того, связанные понятия должны быть близко друг к другу.
Итак, вот надуманный пример, который во многих отношениях плох (плохой дизайн ОО; никогда не используется
double
за деньги), но иллюстрирует идею:Методы упорядочены таким образом, что они близки к тем, которые их вызывают, работая сверху вниз. Если бы мы поместили все
private
методы нижеpublic
тех, которые вам нужны, вам пришлось бы больше прыгать, чтобы следить за ходом программы.getFirstName
иgetLastName
концептуально связаны (и,getEmployeeId
вероятно, тоже), поэтому они близки друг к другу. Мы могли бы переместить их всех вниз, но мы не хотели бы видетьgetFirstName
сверху иgetLastName
снизу.Надеюсь, это даст вам основную идею. Если вы заинтересованы в таких вещах, я настоятельно рекомендую прочитать
Clean Code
.источник
calculateBonus()
прийти раньшеisFullTimeEmployee()
иdidCompleteBonusObjectives()
?isFullTimeEmployee
иdidCompleteBonusObjectives
используютсяisEligibleForBonus
таким образом , они должны быть вертикально близко к нему. Но вы могли быcalculateBonus
подняться, чтобы приблизить его к тому, где он называется. К сожалению, поскольку у вас есть функции, вызывающие функции, в конечном итоге вы сталкиваетесь с проблемами (например, одна общая функция, вызываемая несколькими другими), где нет идеального упорядочения. Тогда это остается на ваше усмотрение. Я рекомендую держать классы и функции небольшими, чтобы смягчить эти проблемы.Я обычно упорядочиваю свои методы по соотношению и порядку использования.
Возьмите сетевой класс, я собираюсь сгруппировать все методы TCP вместе, а затем все методы UDP вместе. Внутри TCP я бы использовал метод установки в качестве первого, возможно, отправлю заданное сообщение вторым и закрою сокет tcp в качестве третьего.
Очевидно, что не все классы будут соответствовать этому шаблону, но это мой общий рабочий процесс.
Я делаю это таким образом, чтобы отлаживать больше всего на свете, когда у меня возникает проблема, и я хочу перейти к методу, я не думаю, как это пишется, я думаю, за что он отвечает, и перехожу к этому разделу.
Этот способ, в частности, имеет смысл для стороннего просмотра / использования вашего кода как сгруппированного вместе и будет следовать порядку его использования, поэтому код, который они напишут с вашим классом, будет следовать той же структуре, что и класс.
Что касается это имеет значение?
для читабельности, безусловно.
кроме этого не совсем, только в тех случаях, когда определенные языки вы не можете вызвать метод, если он не определен выше, где он вызывается и т. д.
источник
В идеале, ваши классы настолько малы, что это не имеет значения. Если у вас есть только дюжина методов, и ваш редактор или IDE поддерживает свертывание, у вас нет проблем, потому что весь список методов помещается в 12 строк.
В противном случае различие на высшем уровне должно быть публичным и частным. Сначала перечислите общедоступные методы: это то, что люди будут искать больше всего, потому что они определяют способ взаимодействия вашего класса с остальной частью кода.
Затем внутри каждого из них имеет смысл сгруппировать методы по функциональности: конструкторы и деструкторы в одном блоке, геттеры / сеттеры в другом, перегрузки операторов, статические методы и остальная часть группы. В C ++ я предпочитаю быть
operator=
ближе к конструкторам, потому что он тесно связан с конструктором копирования, а также потому, что я хочу иметь возможность быстро определить, все ли (или ни один) из ctor по умолчанию, copy ctor, operator = и dtor существует.источник
ТЛ; др
Только если язык, на котором вы работаете, требует определенного заказа. Кроме этого, заказ зависит от вас. Выберите систему, которая является последовательной и имеет смысл, и старайтесь придерживаться ее как можно больше.
Только в том случае, если на языке, с которым вы работаете, должна быть определена функция в файле ранее, чем в том месте, где он вызывается, например, в этом примере:
вы получите ошибку, потому что вы звоните,
funcB()
прежде чем использовать его. Я думаю, что это проблема в PL / SQL и, возможно, в C, но вы можете иметь предварительные объявления, такие как:Это единственная ситуация, о которой я могу подумать, когда, если порядок «неправильный», вы даже не сможете скомпилировать.
В противном случае вы всегда можете заказать их как угодно. Вы могли бы даже написать инструмент, чтобы сделать это для вас (если вы не можете найти его там).
Если язык / окружающая среда не приказывая требования, то «лучший» порядок является тот , который лучше работает для вас . Для меня мне нравится собирать все получатели / установщики вместе, обычно в начале класса (но после конструкторов / статических инициализаторов), а затем закрытые методы, затем защищенные, а затем публичные. В каждой группе, основанной на области действия, обычно нет упорядочения, хотя перегруженные методы я стараюсь хранить вместе в порядке количества параметров. Я также пытаюсь объединить методы со связанной функциональностью, хотя иногда мне приходится нарушать порядок, основанный на области действия; и иногда пытаясь поддерживать упорядочение на основе области действия, групповые по функциональности. И моя IDE может дать мне буквенное представление схемы, так что это тоже хорошо. ;)
Некоторые языки, например C #, имеют возможность группировать код в «регионах» , которые не влияют на компиляцию, но могут упростить объединение связанных функций, а затем скрыть / отобразить их с помощью IDE. Как указала MainMa , есть люди, которые считают это плохой практикой. Я видел хорошие и плохие примеры использования регионов таким образом, поэтому, если вы собираетесь пойти по этому пути, будьте осторожны.
источник