В чем смысл статичности определенных методов для типов данных?

Aug 15 2020

В C #, например, есть статические методы для определения того, является ли строка нулевой или пустой , поиска элемента в массиве, очистки массива и т. Д. Однако существует метод экземпляра для замены символов в строке, причем как статический, так и экземплярный. методы копирования элементов между массивами.

Точно так же в Python есть функции для получения длины списка, для фильтрации списка и т. Д., Но методы экземпляра для поиска индекса элемента и для копирования списка.

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

Так в чем же смысл делать одни вещи статичными, а другие нет?

РЕДАКТИРОВАТЬ : Чтобы быть ясным, я понимаю цель статических методов. Мой вопрос больше касается того, почему определенные методы написаны как статические, хотя их можно было бы написать как методы экземпляра. Как Findдля массивов, так и Formatдля строк в C # filterи lenв Python.

Ответы

2 AvnerShahar-Kashtan Aug 15 2020 at 15:09

РЕДАКТИРОВАТЬ : вопрос был уточнен, поэтому я уточню свой ответ, но оставлю предыдущий ниже, чтобы комментарии не были неуместными.

Может быть несколько причин для реализации метода как статического метода вместо метода экземпляра, с разными языками или фреймворками, возможно, имеющими разные обоснования:

  1. Открытый интерфейс объекта - это контракт. Если ваш Arrayтип предоставляет Sortметод, каждый массив с этого момента, независимо от типа или версии языка, должен его поддерживать. Если, однако, это Arrayпросто представление данных в памяти с тонким контрактом, а логика перемещена в такой класс Array.Sort, это дает вам больше гибкости для расширения или изменения вашего поведения, не нарушая совместимости.

  2. См. Эту цитату из Чистого кода Боба Мартина :

Объекты раскрывают поведение и скрывают данные; Структура данных предоставляет данные и не имеет существенного поведения "

В этом случае Listкласс - это класс, который демонстрирует поведение - он скрывает свои данные (он реализован как массив с изменяемым размером, но это деталь реализации), но предоставляет функциональные возможности. int[], Однако, представляет собой структуру данных. Это последовательно размещенный intблок. У него есть Lengthсвойство, потому что оно является частью его данных , но не имеет особого поведения - поведение передается классу, который с ним работает.

  1. Это может быть стилистический выбор. Python не является чисто объектно-ориентированным языком и может не иметь гарантии Java / C # «все является объектом», поэтому он решил использовать такие языковые функции, len()которые можно использовать независимо от того, является ли его параметр экземпляром объекта или нет.

Предыдущий ответ

Смысл статических методов в C # состоит в том, чтобы иметь методы, которые привязаны к типу, но не к экземпляру . Причин тому может быть несколько:

  1. Методы, которые могут работать как с экземпляром null, так и string.IsNullOrEmpty, естественно, не могут быть методами экземпляра - потому что экземпляра может не быть.
  2. Аналогичным образом фабричные методы, создающие экземпляр, не имеют экземпляра для вызова. Например, устаревший статический WebRequest.Create()метод возвращает новый экземпляр типа, производного от WebRequest.
  3. Хотя об этом легко забыть, но .NET по-разному обрабатывает собственный интегральный тип ( int i =5) и ссылочный тип в рамке вокруг него ( object boxed = 5). Если вы вызываете метод для типа значения ( int i = 5; t.ToString();), вы платите за его упаковку. Вот почему некоторые операции определены не как метод объекта, а как статический метод, который принимает значение. Вот почему математические операции, такие Math.Absкак не определены как методы для упакованных типов, а как статические функции, которые получают и возвращают значения.
  4. Иногда статические методы используются для «настройки» типа, но не одного конкретного экземпляра, а поведения этого типа в системе. Например, [ServicePointManager.SetTcpKeepAlive()][1]настраивает поведение всех классов, которые используют общий стек HTTP (ов) в .NET, поэтому вы можете настроить их все с помощью этих статических методов.
5 amon Aug 15 2020 at 15:28

Статические методы имеют большой смысл

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

C # поддерживает функции только как члены классов, поэтому вспомогательные функции должны быть написаны как статические методы. Класс C # Math- яркий тому пример.

В JavaScript нет классов, но каждая нелокальная переменная связана с некоторым объектом - в браузере большинство API-интерфейсов доступны через windowобъект. Однако есть методы, доступные через объект, подобный классу, например Array.isArray(x).

Python имеет своеобразный дизайн, который в основном объектно-ориентированный, но имеет некоторые встроенные функции, такие как len()или iter(), в основном по историческим причинам. Под капотом они вызывают реальные методы, например, iter(x)как правило x.__iter__(), с резервным вариантом для объектов, которые могут быть проиндексированы как список.

Более интересны методы, которые созданы staticне из-за особенностей языка, а потому, что они имеют смысл. Конструкторские или фабричные методы - классический пример, когда у нас нет существующего объекта, для которого мы могли бы вызвать метод. Некоторые функции также не работают точно с одним объектом, например, String.IsNullOrEmpty(x)работают с нулем или одним объектом. Это не работает как метод, например, x.IsNullOrEmpty()вызовет исключение, если оно равно нулю! Array.isArray(x)Метод JS еще один пример: мы хотим вызвать isArray(x)на объектах любого типа, а не только на массивах. Таким образом, метод экземпляра не работает, если он не является частью прототипа каждого объекта.