В чем разница между двумя методами UpdateSubject ниже? Я чувствовал, что использование статических методов лучше, если вы просто хотите оперировать сущностями. В каких ситуациях мне следует использовать нестатические методы?
public class Subject
{
public int Id {get; set;}
public string Name { get; set; }
public static bool UpdateSubject(Subject subject)
{
//Do something and return result
return true;
}
public bool UpdateSubject()
{
//Do something on 'this' and return result
return true;
}
}
Я знаю, что получу от сообщества много пинков за этот действительно раздражающий вопрос, но я не мог не спросить его.
Становится ли это непрактичным, когда речь идет о наследовании?
Обновление: это
происходит на нашем рабочем месте сейчас. Мы работаем над 6-месячным веб-приложением asp.net с 5 разработчиками. Наш архитектор решил, что мы используем все статические методы для всех API. Его рассуждения о том, что статические методы легки, и приносят пользу веб-приложениям, снижая нагрузку на сервер.
object-oriented
static-methods
Александр
источник
источник
Ответы:
Я пойду с наиболее очевидными проблемами статических методов с явными параметрами "this":
Вы теряете виртуальную диспетчеризацию и впоследствии полиморфизм. Вы никогда не сможете переопределить этот метод в производном классе. Конечно, вы можете объявить метод
new
(static
) в производном классе, но любой код, который обращается к нему, должен знать всю иерархию классов и выполнять явную проверку и приведение, чего в точности следует избегать ОО .Вроде расширения # 1, вы не можете заменить экземпляры класса интерфейсом , потому что интерфейсы (в большинстве языков) не могут объявлять
static
методы.Ненужное многословие. Что более читабельно:
Subject.Update(subject)
или простоsubject.Update()
?Проверка аргументов. Опять же, это зависит от языка, но многие скомпилируют неявную проверку, чтобы убедиться, что
this
аргумент неnull
для того, чтобы предотвратить ошибочную ошибку нулевой ссылки в создании небезопасных условий выполнения (вид переполнения буфера). Не используя методы экземпляра, вы должны явно добавить эту проверку в начале каждого метода.Это сбивает с толку. Когда нормальный, разумный программист видит
static
метод, он, естественно, предполагает, что ему не требуется допустимый экземпляр (если только он не принимает несколько экземпляров, например, метод сравнения или равенства, или ожидается, что он сможет работать соnull
ссылками) , Вид статических методов, используемых таким образом, заставит нас сделать двойной или, возможно, тройной дубль, и после 4-го или 5-го раза мы будем испытывать стресс и злость, и Бог поможет вам, если мы узнаем ваш домашний адрес.Это форма дублирования. Когда вы вызываете метод экземпляра, на самом деле происходит то, что компилятор или среда выполнения ищет метод в таблице методов типа и вызывает его, используя
this
в качестве аргумента. Вы в основном заново реализуете то, что компилятор уже делает. Вы нарушаете DRY , повторяете один и тот же параметр снова и снова разными способами, когда это не нужно.Трудно представить какую-либо вескую причину заменить методы экземпляра статическими методами. Пожалуйста, не надо.
источник
File
,FileInfo
иDirectoryInfo
(и на самом деле, есть библиотеки, которые скрывают их за интерфейсами, которые затем могут вводиться по мере необходимости и проверяться в тестах).Вы в значительной степени описали, как именно вы выполняете ООП в C, в котором доступны только статические методы, а «this» является структурным указателем. И да, вы можете сделать полиморфизм времени выполнения в C, указав указатель функции во время построения, который будет сохранен как один элемент структуры. Методы экземпляров, доступные на других языках, являются просто синтаксическим сахаром, который по сути делает то же самое под капотом. Некоторые языки, такие как python, находятся на полпути между ними, где параметр «self» явно указан, но специальный синтаксис для его вызова обрабатывает наследование и полиморфизм для вас.
источник
obj->type->mthd(obj, ...);
и это в значительной степени похоже на то, что происходит с виртуальной диспетчеризацией на других языках (но за кулисами).Проблема со статическим методом возникает в тот момент, когда вам нужен подкласс.
Статические методы не могут быть переопределены в подклассах, поэтому ваши новые классы не могут обеспечить новые реализации методов, что делает их менее полезными.
источник
Если вы объявляете метод
static
, вам не нужно создавать экземпляр объекта из класса (используяnew
ключевое слово) для выполнения метода. Однако вы не можете ссылаться на какие-либо переменные-члены, если они не являются также статическими, и в этом случае эти переменные-члены принадлежат классу, а не конкретному объекту класса.Другими словами,
static
ключевое слово заставляет объявление быть частью определения класса, поэтому оно становится единой контрольной точкой во всех экземплярах класса (объектах, созданных из класса).Из этого следует, что если вы хотите, чтобы несколько запущенных копий вашего класса и вы не хотели, чтобы состояние (переменные-члены) распределялось между всеми вашими запущенными копиями (т. Е. Каждый объект имеет свое собственное уникальное состояние), то вы не может объявить эти переменные-члены статическими.
В общем случае
static
классы и методы следует использовать только при создании служебных методов, которые принимают один или несколько параметров и возвращают какой-либо объект без каких-либо побочных эффектов (т. Е. Изменения переменных состояния в классе).источник
static
значит, он спрашивает, почему бы просто не объявить все как статичное.Subject
- но в качестве явного параметра, вместо неявногоthis
параметра.this
параметра. Существуют различия в ожиданиях, но за пределами наследования нет реальной разницы в том, что вы можете сделать. Например, к этим нестатическим членам можно получить доступ - через явный параметр.Причина, по которой люди утверждают, что «статические методы демонстрируют плохой дизайн», не обязательно связана с методами, это на самом деле статические данные, неявные или явные. Под неявным я подразумеваю ЛЮБОЕ состояние в программе, которое не содержится в возвращаемых значениях или параметрах. Изменение состояния в статической функции - это возврат к процедурному программированию. Однако, если функция не изменяет состояние или делегирует изменение состояния объектным функциям компонента, на самом деле это скорее функциональная парадигма, чем процедурная.
Если вы не меняете состояние, статические методы и классы могут иметь много преимуществ. Это значительно упрощает обеспечение того, что метод является чистым и, таким образом, не имеет побочных эффектов и любые ошибки полностью воспроизводимы. Это также гарантирует, что различные методы в нескольких приложениях, использующих общую библиотеку, могут быть уверены, что они получат одинаковые результаты при одинаковых входных данных, что значительно упростит как отслеживание ошибок, так и модульное тестирование.
В конечном счете, на практике нет большой разницы между обычно видимыми объектами большого размера, такими как «StateManager», и статическими или глобальными данными. Преимущество статических методов, используемых правильно, заключается в том, что они могут указывать намерение автора не изменять состояние для более поздних редакторов.
источник
making ... unit testing much easier.
Нет, не будет. Это делает невозможным любой код, который вызывает статические методы для модульного тестирования, поскольку вы не можете изолировать его от статического метода. Вызов статического метода становится жестко закодированной зависимостью от этого класса.В зависимости от языка и того, что вы пытаетесь сделать, ответ может быть, что нет большой разницы, но
static
версия имеет немного больше помех.Поскольку ваш примерный синтаксис предлагает Java или C #, я думаю, что Торбьерн Равн Андерсен прав, когда указывает на проблему с переопределением (с поздним связыванием). При статическом методе не существует «специального» параметра для поздней привязки, на котором можно основываться, поэтому у вас не может быть поздней привязки.
По сути, статический метод - это просто функция в модуле, этот модуль имеет то же имя, что и класс - на самом деле это вовсе не метод ООП.
источник
Вы в основном побеждаете весь смысл объектов, когда делаете это. Есть веская причина, по которой мы в значительной степени перешли от процедурного кода к объектно-ориентированному коду.
Я НИКОГДА не объявляю статический метод, который принимает тип класса в качестве параметра. Это просто делает код более сложным без выгоды.
источник
object
кstatic
способу, и возвращая новыйobject
. Функциональные программисты делают это постоянно.Math
статический класс «сложным без выгоды», или вы бы предпочли, чтобы у всех типов чисел были виртуальные методы, определяющие абсолютное значение, отрицание, сложение, возведение в квадрат, произвольные корни и т. д.? Я так не думаю. Объекты аккуратны, когда вам нужно сохранить скрытое изменяемое состояние, где вам нужно применить некоторые инварианты. объединяя каждый возможный метод, который работает с типом, в сам тип, это то, что приводит к сложному и не поддерживаемому коду. Я согласен с Робертом, вы можете взглянуть на то, как работают функциональные программисты, это может стать настоящим откровением!Здесь много хороших ответов, и они намного более проницательны и хорошо осведомлены, чем все, что я когда-либо мог придумать в качестве ответа, но я чувствую, что есть кое-что, на что не обращают внимания:
«Наш архитектор решил, что мы используем все статические методы для всех API. Его аргументы в пользу того, что статические методы легки и полезны для веб-приложений, снижают нагрузку на сервер ».
(жирный акцент мой)
Мой 2с по этой части вопроса таков:
Теоретически, то, что сказано, верно: вызов статического метода имеет только накладные расходы на фактический вызов этого метода. Вызов нестатического (экземпляра) метода имеет дополнительные издержки, связанные с первым созданием экземпляра объекта и, в какой-то момент, уничтожением экземпляра (либо вручную, либо с помощью некоторой формы автоматического сбора мусора, в зависимости от используемой платформы).
Спектакль немного отстаивает дьявола на этом: мы можем пойти еще дальше и сказать такие вещи, как:
это может стать очень плохим, если экземпляр создается для каждого вызова метода (экземпляра) (в отличие от просто оставления статического состояния и вызова его таким образом)
в зависимости от сложности конструктора, иерархии типов, других членов экземпляра и других подобных неизвестных факторов дополнительные издержки при вызове нестатического метода могут варьироваться и становиться действительно большими
По правде говоря, ИМХО, вышеупомянутые пункты (и общий подход «давайте использовать статику, потому что они быстрее») являются аргументами / оценками соломенного человека:
если код хороший и, более конкретно, для этого аргумента, если экземпляры создаются только при необходимости (и уничтожаются оптимальным образом), то вы не получаете никаких дополнительных затрат от использования методов insance, когда это уместно (потому что если вы создавать только необходимые объекты, они были бы созданы, даже если бы этот метод был объявлен как static, где else = те же самые издержки инстанцирования)
злоупотребляя объявлением статических методов таким образом, можно скрыть некоторые проблемы с вашим кодом в отношении того, как создаются экземпляры (поскольку метод является статическим, неправильный код экземпляра может пройти незамеченным до позднего времени, и это никогда не бывает хорошо).
источник
Это очень интересный вопрос, ответы на который, как правило, очень разные, в зависимости от того, в каком сообществе вы его задаете. Другие ответы кажутся C # или java bias: язык программирования, который (в основном) чисто объектно-ориентирован и имеет своего рода идиоматическое представление о том, что такое объектная ориентация.
В других сообществах, таких как C ++, объектная ориентация интерпретируется с большей либеральностью. Некоторые хорошо известные эксперты изучили предмет и, на самом деле, пришли к выводу, что свободные функции улучшают инкапсуляцию (акцент мой):
Для тех, кто не знаком с терминологией C ++:
Теперь, чтобы ответить на ваш вопрос:
Нет, вы не всегда должны использовать статические методы.
Но вы должны использовать их всякий раз, когда вам нужно использовать только открытый API класса.
источник
на Яве ...
Статические методы не перезаписываются, а скрываются, поэтому в случае расширения класса будет большая разница (проблема?).
С другой стороны, я заметил, что Java-программисты склонны думать, что все ДОЛЖНО быть объектом, не понимая, почему, и я не согласен.
Статика должна использоваться для кода, специфичного для класса. Статика плохо работает с наследованием.
Некоторые хорошие примеры использования статических методов - это независимые функции без побочных эффектов.
также см. ключевое слово синхронизировано ...
источник