Мне нужно объяснить себе, почему я не использую статические методы / свойства. Например,

String s=String.Empty;

Это свойство (принадлежит .Net framework) неверно? это должно быть похоже?

String s= new EmptySting();

Или

IEmptyStringFactory factory=new EmptyStringFactory();

String s= factory.Create();
3
Sessiz Saat 7 Июл 2009 в 18:12

9 ответов

Лучший ответ

Я думаю, что худшее в использовании статики - это то, что вы можете получить тесную связь между классами. См. ASP.NET до выхода System.Web.Abstractions. Это затрудняет тестирование ваших классов и, возможно, делает их более подверженными ошибкам, вызывающим общесистемные проблемы.

7
user1228user1228 7 Июл 2009 в 14:15

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

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

(Лично я предпочитаю использовать "" вместо string.Empty, но это обсуждение, которое было до смерти в другом месте.)

9
Jon Skeet 7 Июл 2009 в 18:17

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


String s=String.Empty;

Это синглтон. Вы могли бы использовать это, когда хотите убедиться, что есть только одно из чего-то. В этом случае, поскольку строка неизменяема, всегда должна быть только одна «пустая» строка. Не злоупотребляйте синглтонами, потому что их сложно протестировать. Однако, когда они имеют смысл, они очень сильны.


String s= new EmptySting();

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


IEmptyStringFactory factory=new EmptyStringFactory();
String s= factory.Create();

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

Если создание объекта зависит от состояния, которое может быть неизвестно вызывающему, тогда вам следует использовать фабрики экземпляров (как в вашем примере). Если конструкция сложная, но вызывающий знает условия, которые могут повлиять на построение, тогда вам следует использовать статическую фабрику (например, StringFactory.CreateEmpty() или StringFactory.Create("foo"). Однако в случае строки конструкция достаточно просто, чтобы использование фабрики пахло решением, ищущим проблему.

2
Michael Meadows 7 Июл 2009 в 14:49

Как правило, создавать новую пустую строку - плохая идея - это создает дополнительные объекты в куче, поэтому сборщик мусора требует дополнительной работы. Вы всегда должны использовать String.Empty или "", когда вам нужна пустая строка, поскольку это ссылки на существующие объекты.

1
thecoop 7 Июл 2009 в 14:17

В общем, цель статики - убедиться, что в вашей программе всегда есть только один экземпляр статической «вещи».

  • Статические поля сохраняют одно и то же значение во всех экземплярах типа.
  • Статические методы и свойства не нуждаются в экземпляре для вызова
  • Статические типы могут содержать только статические методы / свойства / поля.

Статика полезна, когда вы знаете, что создаваемая вами «вещь» никогда не изменится за время существования программы. В вашем примере System.String определяет частное статическое поле для хранения пустой строки, которая выделяется только один раз и предоставляется через статическое свойство.

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

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

1
Steve Guidi 7 Июл 2009 в 14:40

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

Способ совместного использования общего объекта и разрешения нескольким субъектам на его состояние - передать ссылку.

Основная проблема со статическими методами заключается в том, что, если в будущем вам понадобятся два из них? Мы пишем компьютерные программы, можно было бы предположить, что если мы можем сделать одно из чего-то, мы сможем сделать два очень просто, со статикой это не так. Чтобы изменить что-либо из статического состояния в нормальное состояние экземпляра, необходимо полностью переписать рассматриваемый класс.

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

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

1
clemahieu 7 Июл 2009 в 15:19

У использования статики есть недостатки, такие как:

  1. Статика не позволяет использовать методы расширения.
  2. Статический конструктор вызывается автоматически для инициализации класса перед созданием первого экземпляра (конечно, в зависимости от вызываемого статического класса)
  3. Данные статического класса живут в течение всего срока действия области выполнения, это тратит впустую память.

Причины использования статических методов

  1. Статика хороша для вспомогательных методов, поскольку вы не хотите создавать локальную копию нестатического класса только для вызова единственного вспомогательного метода.
  2. Eeerm, статические классы делают возможным шаблон singleton.
1
Neil 7 Июл 2009 в 16:29

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

Еще один полезный критерий здесь - правильность распределения ответственности. Например, у вас есть класс учетной записи. Скажем, вам нужна функция для конвертации валюты, например от долларов до евро. Вы делаете это членом класса Account? account.ConvertTo (Currency.Euro)? Или вы создаете другой класс, который инкапсулирует эту ответственность? CurrencyConverter.Convert (счет, Currency.Euro)? Для меня последний вариант лучше в том смысле, что он включает обязанности другого класса, в то время как в первом случае я буду распространять знания о конвертации валют по разным учетным записям.

0
Ariel 7 Июл 2009 в 18:46

Что ж, в случае String.Empty это скорее константа (вроде как Math.PI или Math.E) и определена для этого типа. Создание подкласса для одного конкретного значения обычно плохо.

Перейдем к другому (главному) вопросу о том, насколько они «неудобны»:

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

Большинство моих статических членов являются либо константами, как указано выше, либо фабричными методами (например, Int.TryParse).

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

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

Например, я хотел бы сказать следующее:

Math mD = new Math(AngleMode.Degrees); // ooooh, use one with degrees instead
double x = mD.Sin(angleInDegrees);

Но вместо этого я должен написать это:

double x = Math.Sin(angleInDegrees * Math.PI / 180);

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

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

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

2
Erich Mirabal 7 Июл 2009 в 14:40