Мне очень любопытны мысли и лучшие отраслевые практики, касающиеся статических членов или целых статических классов. Есть ли какие-либо недостатки в этом, или это участвует в каких-либо анти-паттернах?
Я рассматриваю эти сущности как «служебные классы / члены» в том смысле, что они не требуют или не требуют создания экземпляров класса для обеспечения функциональности.
Каковы общие мысли и лучшие отраслевые практики по этому поводу?
Посмотрите приведенные ниже примеры классов и членов, чтобы проиллюстрировать, на что я ссылаюсь.
// non-static class with static members
//
public class Class1
{
// ... other non-static members ...
public static string GetSomeString()
{
// do something
}
}
// static class
//
public static class Class2
{
// ... other static members ...
public static string GetSomeString()
{
// do something
}
}
Заранее спасибо!
c#
class-design
Томас Стрингер
источник
источник
Ответы:
В общем, избегайте статики - особенно любого статического состояния.
Зачем?
Статика вызывает проблемы с параллелизмом. Поскольку существует только один экземпляр, он, естественно, распределяется между параллельным выполнением. Эти общие ресурсы - проклятие параллельного программирования, и часто их не нужно совместно использовать.
Статика вызывает проблемы с юнит-тестированием. Любой фреймворк для модульного тестирования, достойный солевой проверки, запускается одновременно. Тогда вы столкнетесь с # 1. Хуже того, вы усложняете свои тесты всем, что связано с настройкой / разборкой, и хакерством, с которым вы столкнетесь, пытаясь «поделиться» кодом установки.
Есть много маленьких вещей тоже. Статика имеет тенденцию быть негибкой. Вы не можете связать их, вы не можете переопределить их, вы не можете контролировать время их создания, вы не можете использовать их в генериках. Вы не можете реально их версии.
Конечно, есть статика: постоянные значения работают отлично. Чистые методы, которые не вписываются в один класс, могут отлично работать здесь.
Но в целом избегайте их.
источник
volatile
. Вы просто не получаете никаких гарантий от модели памяти без изменчивых данных, поэтому изменение переменной в одном потоке может не отражаться сразу или вообще.Если функция "чистая", я не вижу проблем. Чистая функция действует только во входных параметрах и обеспечивает результат на основе этого. Это не зависит от какого-либо глобального состояния или внешнего контекста.
Если я посмотрю на ваш собственный пример кода:
Эта функция не принимает никаких параметров. Таким образом, это, вероятно, не чисто (единственной чистой реализацией этой функции будет возвращение константы). Я предполагаю, что этот пример не является представителем вашей реальной проблемы, я просто указываю, что это, вероятно, не чистая функция.
Давайте возьмем другой пример:
Нет ничего плохого в том, что эта функция статична. Мы могли бы даже превратить это в функцию расширения, позволяющую клиентскому коду стать еще более читабельным. Функции расширения - это просто особый вид статических функций.
Теластин правильно упоминает параллелизм как потенциальную проблему со статическими членами. Однако, поскольку эта функция не использует разделяемое состояние, здесь нет проблем с параллелизмом. Тысячи потоков могут вызывать эту функцию одновременно без проблем с параллелизмом.
В .NET Framework методы расширения существуют уже довольно давно. LINQ содержит множество функций расширения (например, Enumerable.Where () , Enumerable.First () , Enumerable.Single () и т. Д.). Мы не считаем это плохим, не так ли?
Модульное тестирование часто может принести пользу, когда в коде используются заменяемые абстракции, что позволяет модульному тесту заменить системный код на двойной тест. Статические функции запрещают эту гибкость, но это в основном важно на границах архитектурного уровня, где мы хотим заменить, например, реальный уровень доступа к данным на поддельный уровень доступа к данным.
Однако при написании теста для объекта, который ведет себя по-разному, в зависимости от того, является ли какое-то число нечетным или четным, нам на самом деле не нужно иметь возможность заменить
IsOdd()
функцию альтернативной реализацией. Кроме того, я не вижу, когда нам нужно предоставить другуюEnumerable.Where()
реализацию для тестирования.Итак, давайте проверим читабельность клиентского кода для этой функции:
Вариант а (с функцией, объявленной как метод расширения):
Вариант б:
Функция static (extension) делает первый фрагмент кода намного более читабельным, а удобочитаемость очень важна, поэтому используйте статические функции там, где это необходимо.
источник