Выполнение использования статических методов против экземпляра класса, содержащего методы

Я работаю над проектом на С#. Предыдущий программист не знал объектно-ориентированного программирования, поэтому большая часть кода находится в огромных файлах (мы говорим о 4-5000 строк), которые распространяются по десяткам, а иногда и по сотням методов, но только по одному классу. Рефакторинг такого проекта - грандиозное мероприятие, и поэтому я уже давно научился жить с ним.

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

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

Ответ 1

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

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

Ответ 2

Я столкнулся с аналогичной проблемой, когда я работаю. Передо мной программист создал 1 класс контроллера, где были сброшены все функции BLL.

Мы сейчас перепроектируем систему и создали много классов контроллера в зависимости от того, что они должны контролировать, например.

UserController, GeographyController, ShoppingController...

Внутри каждого класса контроллера есть статические методы, которые делают вызовы кэш-памяти или DAL с использованием шаблона singleton.

Это дает нам 2 основных преимущества. Это немного быстрее (примерно в 2-3 раза быстрее, но здесь говорили наносекунды, P). Другим является то, что код намного чище.

i.e

ShoppingController.ListPaymentMethods()

вместо

new ShoppingController().ListPaymentMethods()

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

Ответ 3

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

Тем не менее, это не похоже, что производительность - это ваша самая большая проблема прямо сейчас.

Ответ 4

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

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

Кроме того, если вы должны следовать хорошим принципам OO (см. SOLID в http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29) и/или использовать шаблоны проектирования, вы, безусловно, будете делая много основанных на экземплярах, основанных на интерфейсах, и не используя много статических методов.

Что касается этого предложения:

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

Я вижу это много в сетевых сетях с точками, и для меня это нарушает инкапсуляцию, ключевую концепцию OO. Я не могу определить, имеет ли метод побочные эффекты, является ли метод статическим. Помимо разрыва инкапсуляции это означает, что вам нужно будет менять методы от статического к экземпляру, если/когда вы их модифицируете, чтобы иметь побочные эффекты. Я предлагаю вам прочитать принцип Open/Closed для этого и посмотреть, как работает этот подход, приведенный выше, с учетом этого.

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

Ответ 5

Я думаю, вы частично ответили на этот вопрос так, как вы его спросили: есть ли заметные штрафы за производительность в коде, который у вас есть?

Если штрафы не заметны, вам не обязательно обязательно что-либо делать. (Хотя само собой разумеется, что кодовая база в значительной степени выиграла бы от постепенного рефакторинга в респектабельную модель OO).

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

Ответ 6

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

Оттуда вы можете медленно перемещать область этих объектов поменьше и меньше, пока не получите достойный дизайн ООП.

Тогда опять подход, который я, вероятно, использовал бы, отличается;).

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

Что касается аспекта производительности вопроса, статические методы должны быть немного быстрее (но не так много), поскольку они не связаны с построением, передачей и деконструкцией объекта.

Ответ 7

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

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

ShapeUtils.DrawCircle(stroke, pen, origin, radius);

ShapeUtils.DrawSquare(stroke, pen, x, y, width, length);

VS

ShapeUtils utils = new ShapeUtils(stroke,pen);

util.DrawCircle(origin,radius);

util.DrawSquare(x,y,width,length);

В этом случае, всякий раз, когда переменные экземпляра используются всеми методами большую часть времени, методы экземпляров очень ценны. Экземпляры НЕ ОБЩЕГО СОСТОЯНИЯ, это ОБ ОБМЕНАХ, хотя ОБЩЕЕ СОСТОЯНИЕ - это естественная форма ОБМЕНА, они НЕ ТАКИЕ. Общее эмпирическое правило таково: если метод тесно связан с другими методами - они любят друг друга так сильно, что они, когда их зовут, должны быть вызваны и другие, и они, вероятно, разделяют одну и ту же чашку воды - -, это должно быть сделано экземпляром. Переводить статические методы в методы экземпляров не так сложно. Вам нужно только взять общие параметры и поместить их в качестве переменных экземпляра. С другой стороны, сложнее.

Или вы можете создать прокси-класс, который приведет к преодолению статических методов. Хотя это может показаться более неэффективным в теории, практика говорит о другой истории. Это происходит потому, что всякий раз, когда вам нужно вызвать DrawSquare один раз (или в цикле), вы переходите прямо к статическому методу. Но всякий раз, когда вы будете использовать его снова и снова вместе с DrawCircle, вы будете использовать прокси-сервер экземпляра. Примером может служить класс System.IO FileInfo (экземпляр) vs File (статический).

Статические методы можно проверить. На самом деле, еще более проверяемым, чем один экземпляр. Метод GetSum (x, y) будет очень подвержен тестированию не только unit test, но и нагрузочного теста, интегрированного теста и теста использования. Методы экземпляров хороши для тестов единиц, но ужасны для всех других тестов (что имеет значение больше, чем единицы тестов BTW), поэтому в наши дни у нас так много ошибок. Вещь, которая делает ALL Methods untestable, - это параметры, которые не имеют никакого смысла (Sender s, EventArgs e) или глобального состояния, такого как DateTime.Now. На самом деле, статические методы настолько хороши в тестируемости, что вы видите меньше ошибок в коде C нового дистрибутива Linux, чем ваш средний программист OO (он полный s ***, я знаю).