Думки та найкращі практики щодо статичних класів та членів [закрито]


11

Мені дуже цікаво щодо думок і кращих практик в галузі статичних членів або цілих статичних класів. Чи є якісь недоліки у цьому чи вона бере участь у будь-яких анти-моделях?

Я розглядаю ці сутності як "класи / члени корисних програм", в тому сенсі, що вони не вимагають і не вимагають інстанціювати клас для забезпечення функціональності.

Які загальні думки та передовий досвід галузі?

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

// 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
    }
}

Заздалегідь спасибі!


1
Стаття MSDN про статичні класи та статичні методи забезпечує досить хороше лікування.
Роберт Харві

1
@ Роберт Харві: Хоча стаття, на яку ви посилалися, є корисною, вона не дає великого значення з точки зору найкращих практик та деяких підводних каменів при використанні статичних класів.
Бернард

Відповіді:


18

Взагалі уникайте статики - особливо будь-якого статичного стану.

Чому?

  1. Статистика викликає проблеми з одночасністю. Оскільки існує лише один екземпляр, він, природно, поділяється між паралельним виконанням. Ці спільні ресурси є основою паралельного програмування, і часто їх не потрібно ділити.

  2. Статистика спричиняє проблеми при тестуванні одиниць. Будь-яка одиниця тестування одиниць, яка вартує солі, виконує тести одночасно. Тоді ви натрапляєте на №1. Що ще гірше, ви ускладнюєте свої тести з усіма параметрами налаштування / прострочення, а також хакером, який ви потрапите, щоб спробувати і "поділитися" інсталяційним кодом.

Також є маса дрібниць. Статика, як правило, негнучка. Ви не можете інтерфейсувати їх, ви не можете їх переосмислити, ви не можете контролювати терміни їх побудови, ви не можете добре використовувати їх у генеріках. Ви не можете реально їх версії.

Звичайно, є статистика: постійні значення чудово працюють. Чисті методи, які не вписуються в один клас, можуть чудово працювати тут.

Але загалом уникайте їх.


Мені цікаво, наскільки ви хочете мати на увазі паралельність. Чи можете ви розширити це? Якщо ви маєте на увазі, що до членів можна отримати доступ без сегрегації, це має ідеальний сенс. Ваші випадки використання статики - це те, для чого я їх зазвичай використовую: постійні значення та чисті / корисні методи. Якщо це найкращий та 99-відсотковий кейс для статики, то це дає мені рівень комфорту. Також +1 для вашої відповіді. Чудова інформація.
Томас Стрінгер

@ThomasStringer - тільки те, що чим більше точок дотику між потоками / завданнями означає більше можливостей для проблем одночасності та / або більшої втрати продуктивності при синхронізації.
Теластин

Отже, якщо один потік зараз отримує доступ до статичного члена, то іншим потокам потрібно чекати, поки власний потік не звільнить ресурс?
Томас Стрінгер

@ThomasStringer - може, може і ні. Статистика (майже майже на більшості мов) нічим не відрізняється від будь-якого іншого спільного ресурсу в цьому плані.
Теластин

@ThomasStringer: На жаль, це насправді гірше цього, якщо ви не позначили члена volatile. Ви просто не отримуєте жодних гарантій з моделі пам’яті без нестабільних даних, тому зміна змінної в одному потоці може відображатися не відразу або зовсім.
Фоши

17

Якщо функція "чиста", я не бачу проблем. Чиста функція працює лише у вхідних параметрах і забезпечує результат, заснований на цьому. Це не залежить від будь-якого глобального стану чи зовнішнього контексту.

Якщо я дивлюсь на приклад власного коду:

public class Class1
{
    public static string GetSomeString()
    {
        // do something
    }
}

Ця функція не приймає жодних параметрів. Таким чином, він, ймовірно, не є чистим (єдиною чистою реалізацією цієї функції було б повернення константи). Я припускаю, що цей приклад не є репрезентом вашої реальної проблеми, я просто вказую, що це, мабуть, не є чистою функцією.

Давайте візьмемо інший приклад:

public static bool IsOdd(int number) { return (number % 2) == 1; }

Немає нічого поганого в тому, що ця функція є статичною. Ми могли навіть перетворити це на функцію розширення, що дозволяє клієнтському коду стати ще читабельнішим. Функції розширення - це в основному лише особливий вид статичних функцій.

Теластин правильно згадує одночасність як потенційну проблему зі статичними членами. Однак, оскільки ця функція не використовує загальний стан, тут немає проблем з одночасністю. Тисяча ниток може викликати цю функцію одночасно без жодних проблем одночасності.

У .NET рамках методи розширення існують досить давно. LINQ містить безліч функцій розширення (наприклад, Enumerable.Where () , Enumerable.First () , Enumerable.Single () тощо). Ми не вважаємо це поганим, чи не так?

Тестування одиниць часто може отримати користь, коли код використовує змінні абстракції, що дозволяє тесту блоку замінити системний код тестовим подвійним. Статичні функції забороняють цю гнучкість, але це головне важливо на межах архітектурного рівня, де ми хочемо замінити, наприклад, фактичний рівень доступу до даних фальшивим рівнем доступу до даних.

Однак, коли пишемо тест для об'єкта, який веде себе по-різному, залежно від того, чи якесь число непарне чи парне, нам насправді не потрібно мати можливість замінити IsOdd()функцію альтернативною реалізацією. Так само я не бачу, коли нам потрібно надати іншу Enumerable.Where()реалізацію для тестування.

Тож давайте вивчимо читабельність коду клієнта для цієї функції:

Варіант a (з функцією, оголошеною як метод розширення):

public void Execute(int number) {
    if (number.IsOdd())
        // Do something
}

Варіант b:

public void Execute(int number) {
    var helper = new NumberHelper();
    if (helper.IsOdd(number))
        // Do something
}

Функція статичного (розширення) робить перший фрагмент коду набагато більш читабельним, а читабельність має велике значення, тому використовуйте статичні функції, де це доречно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.