Не використовуйте "Static" в C #?


109

Я подав заявку, яку я написав іншим архітекторам на перевірку коду. Один з них майже одразу написав мені відповідь і сказав: "Не використовуйте" статичні ". Ви не можете писати автоматичні тести зі статичними класами та методами." Статичного "слід уникати".

Я перевірив і повністю 1/4 моїх занять позначені "статично". Я використовую статику, коли я не збираюся створювати екземпляр класу, оскільки клас - це єдиний глобальний клас, який використовується в коді.

Він продовжував згадувати щось, що стосується глузування, методів IOC / DI, які не можна використовувати зі статичним кодом. Він каже, що прикро, коли сторонні бібліотеки є статичними через їх неперевіреність.

Правильний цей інший архітектор?

оновлення: ось приклад:

APIManager - цей клас зберігає словники сторонніх API, які я дзвоню разом із наступним дозволеним часом. Він застосовує ліміти використання API, які мають багато третіх сторін у своїх умовах надання послуг. Я використовую його де завгодно, я телефоную сторонній службі, зателефонувавши Thread.Sleep (APIManager.GetWait ("ProviderXYZ")); перед тим, як телефонувати. Тут все безпечно для потоків, і це чудово працює з TPL в C #.


37
staticдобре; static з полями потрібно поводитися дуже обережно
Марк Гравелл

2
Чому він писав би тести для сторонніх бібліотек? Ви зазвичай не перевіряєте власний код, припускаючи, що творці сторонньої бібліотеки провели тестування?
Nope

3
Це особливе заперечення для мене занадто загальне. У більшості випадків ви не макетуєте статичний клас, ви глузуєте з аргументів. Статичне поле, де це був сукупний клас, який потребував глузування, тоді так.

8
Очевидно, що у ваших колег важкий стан - гострий системний еритематоз OOPus. Вони потребують лікування як можна швидше!
SK-логіка

6
Є розділ відповідей для надання відповідей, я не розумію, чому люди коментують, намагаючись надати комусь відповідь / пропозицію ... Це перемагає мету StackExchange, безумовно, коментар буде запитувати додаткову інформацію.
петески

Відповіді:


121

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


111
Правильно. Статичні функції, які не мають побічних ефектів, є найбільш перевіреними функціями з усіх.
Роберт Харві

9
+1 до цього, але із застереженням безпеки: Майже кожен абстрактний алгоритм є без громадянства, але це не означає, що слід реалізовувати його як статичний клас або метод без громадянства. Реалізуючи його таким чином, усі коди, що використовують його, майже не пов'язані з ним. Це означає, наприклад, що якщо ви реалізуєте алгоритм сортування як статичний метод і використовуєте його через проект - ви не можете тимчасово замінити сортування на інший алгоритм, тобто для цілей тестування та для звуження проблемної області. Це величезна перешкода у багатьох випадках. Окрім цього, статичний є цілком нормальним, якщо використовувати його розумно.

11
Коротше кажучи: вони є найбільш тестованими функціями, але це не обов'язково, вони роблять інший код більш перевіреним! Це, мабуть, мав на увазі архітектор.

4
@ tereško: Мова C # вимагає, щоб статичні методи були частиною статичного класу, якщо вам не потрібно створювати екземпляр класу для виклику методу. Можливо, ви маєте на увазі "екземпляр", а не "клас".
Роберт Харві

8
@quetzalcoatl: Цілком законно передавати делегата (тобто іншого алгоритму) статичному методу; методи розширення в Linq - це всі статичні методи. Приклад: msdn.microsoft.com/en-us/library/…
Роберт Харві

93

Він надто загальний щодо цього. Він правильний, це перешкоджає тестуванню. Однак staticзаняття та методи мають своє місце, і це дійсно залежить від контексту. Без прикладів коду ви справді не можете сказати.

Я використовую статику, коли я не збираюся створювати екземпляр класу, оскільки клас - це єдиний глобальний клас, який використовується в коді.

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

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


3
+1 для згадки про те, що твердження було загальним та згадуванням методів розширення, які також можна перевірити, і наскільки залежністю все ще можна глузувати, наскільки я знаю.
Nope

4
Який статичний екземпляр класу, як неявний синглтон, це стане безладним ....

"Для доступу до бази даних?" чому ні ? якщо адаптер таблиці не є статичним, тоді створюється статичний клас @ сильно набраний набір даних, нічого поганого в цьому немає .... якщо ви не докажете свою точку посиланням чи прикладом?
Математика

27

Я перевірив і повністю 1/4 моїх занять позначені "статично". Я використовую статику, коли я не збираюся створювати екземпляр класу, оскільки клас - це єдиний глобальний клас, який використовується в коді.

Найкраще зробити це - спробувати і протестувати свій код. Спробуйте спроектувати тести, які повторюються, незалежні, прості та перевіряйте лише один метод. Спробуйте запустити тести в іншому рандомізованому порядку. Чи можете ви отримати стабільну "зелену" збірку?

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


7
Це пункт, який вразив і мене. Кілька занять у стилі "помічники" статичного та без громадянства - це добре, але якщо ви отримаєте повних 25% усіх класів як статичні, навряд чи ваші зусилля обмежуються саме цим випадком.
Меттью Шарлі

2
@MatthewScharley - він, мабуть, отримав 4 класи, і 1 з них - статичний :)
Alexus

1
Слідкуйте за тим, що якщо ви використовуєте такі штрихи (наприклад, одиночні кнопки), то пізніше створити більше екземплярів може бути важкою роботою. Як, наприклад, зробивши програму, яка обробляє документ, у вас виникнуть проблеми пізніше, коли ви хочете керувати кількома документами.
Мішель Кейзерс

11

Вже опубліковані відповіді охоплюють багато справді хороших моментів, але, схоже, цього немає:

Статичні поля ніколи не збирають сміття.

Це дійсно важливо, якщо у вас є додаток з великою кількістю обмежень пам'яті, і ця модель може бути дуже поширеною, коли люди намагаються реалізувати кеш.

Статичні функції не так вже й погані, але всі інші вже досить детально висвітлювали це.


10

Однією з переваг, які ви отримуєте від IoC / DI, є те, що більшість взаємодій між класами узгоджується між інтерфейсами. Це полегшує тестування одиниць, оскільки інтерфейси можна знущатися автоматично або напівавтоматично, і тому кожна з деталей може бути протестована на входи та виходи. Крім того, крім testabilty, розміщення інтерфейсів між усім дозволяє вам отримати максимально модульний код - ви можете легко замінити одну реалізацію, не маючи особливих переживань, що ви підкручуєте залежності.

Оскільки у C # немає метакласів, клас не може реалізувати інтерфейс, використовуючи статичні функції, тому статичні особливості класів закінчуються будь-якими зусиллями для реалізації чистої об'єктної моделі IoC / DI. Тобто ви не можете створити макет, щоб перевірити їх, і ви повинні створити реальні залежності.

Якщо ваша компанія / проект вкладають значні кошти в ІОК, це, звичайно, викликає серйозне занепокоєння, і біль, який ви переживаєте, приносить користь усім. Однак, з архітектурної точки зору, я особисто не вважаю, що будь-яку модель слід дотримуватись до глибини. Є деякі речі, які мають сенс реалізувати за допомогою статичних методів - наприклад, стратегія однотонного проектування. Я менш схильний до статичних класів, тому що думаю, що вони, як правило, починають втрачати переваги ОО, але бувають випадки, коли клас бібліотеки, мабуть, є більш природним виразом чогось, ніж двигуна.


Commenter нагадує мені про методи розширення, які, звичайно, повинні бути в статичних класах у C #. Це законно, і це приклад того, як чистий IoC не працює надто добре в C #, принаймні, якщо ви намагаєтесь скористатися широтою мови.


1
Якщо клас зроблено статичним з правильних причин і правильно його реалізує, наприклад, наприклад, методи розширення, вони все ще дуже перевіряються, оскільки вони не мали б зовнішніх залежностей і є самостійними, і як такі не повинні вимагати глузування. Якщо потреба в інтерфейсі не обумовлюється вимогою дизайну, щоб найкраще заповнити бізнес-вимогу не заради збереження чистого проекту IoC / DI?
Nope

1
Ми з вами погоджуємось із загальним пунктом, що ви повинні вибрати правильний інструмент для правильної роботи, а не надягати на себе філософію. Якщо, однак, у вашому проекті чистого IoC / DI існує добре сформована культура, це зашкодить так само, як перетворення традиційного рішення згори вниз в IoC / DI. Інженерія повинна враховувати перехідні витрати. Між іншим, я не думаю, що методи розширення вас цілком не приведуть. Я думаю, що кращим рішенням поведінки IoCish зі статичними класами було б мати декілька класів, обраних між часом компіляції з директивами препроцесора, стиль C
jwrush

1
Ер. Я німий. Ви мали на увазі статичний клас для методів розширення HOLDING, що, звичайно, так і потрібно робити. Так, звичайно, ви хочете статичний клас для цієї мети. Це спалахнуло мені: і це свідчить про те, що C # не призначений для IoC. :)
jwrush

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

5

Статичні класи іноді неправильно використовуються і повинні:

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

Це також може бути так звана функція «утиліта» і частина класу корисності. Класи утиліти - це класи, які містять лише статичні методи і служать допоміжними функціями без будь-якого контексту.


@topomorto Оскільки клас не повинен бути ініційований конструктором, що призводить до декількох об'єктів / екземплярів, а спеціальним методом (як правило, екземпляр ()), який повертає завжди той самий екземпляр, інстанційований після першого виклику до екземпляра ().
Мішель Кейзерс

@topomorto Я щойно перевірив, і ви абсолютно праві, лише деякі члени є статичними (змінна інстанція та функція екземпляра). Я відповідно зміню свою відповідь; дякую за згадування.
Мішель Кейзерс

4

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


1

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

Приклад PHP:

class vendorData {
  private static $data_table = 'vendor_data'; // static property
  private $id; // instance property
  private $name; // instance property

  public function __construct($vendor_id) {
    if(!self::validId($vendor_id) ) { // static method
      return false; // id doesn't exist
    }
    $this->id = $vendor_id; // id has been validated
    $this->getProperties(); // object method
  }

  private static function validId($vendor_id) {
    // send db query to find if the id exists
    // return true/false;
  }

  private function getProperties() { // object method
    $sql = "SELECT * FROM `{self::$data_table}` // using static property
        WHERE `id` = {$this->id}"; // using object instance property
    // get resultset
    foreach($result as $property => $value) {
      $this->$property = $value; // object instance properties all set
    }
  }

  // and here
  public static function getBy($property,$value) { // static method to return object array
    $sql = "SELECT `id` FROM `{self::$data_table}` // using static property
      WHERE `$property` = '$value'";
    // send query, get $ids array
    $obj_array = array();
    foreach($ids as $id) {
      // create array of current class objects using special static keyword
      // meaning of static here is different than in property/method declarations
      $obj_array[$id] = new static($id);
    }
    return $obj_array;
  }
}

1

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


-3

Заняття статичними методами зловживають принципами ООП. Це вже не ООП, це програмування, орієнтоване на клас COP.

Вони рідко мають чітку "особистість" (тут я використовую свою улюблену людську метафору ) або ідентичність. Тому вони не знають, хто вони. Одного лише цього достатньо, щоб позбутися цієї концепції в ООП, але їх більше.

Наступний - наслідок першого пункту. Оскільки такі заняття не знають, хто вони, вони, як правило, від великого до величезного.

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

Повільно, але неминуче ваш код стає все менш згуртованим, оскільки приховані залежності погано контролюються. Вони здаються невидимими. І так просто додати ще одну! Вам не потрібно змінювати підпис жодного методу. Все, що вам потрібно зробити - це викликати статичний метод. І з чого випливає потворний код ...

Гаразд, ви, мабуть, уже здогадалися. Щільна муфта є частою присутністю низької згуртованості. Якщо є багато клієнтів, які використовують якийсь клас, то зчеплення стає все жорсткішим. І є велике спокушання у використанні вже написаного класу чи методу, який вимагає лише крихітного виправлення. Лише один метод-прапор-параметр.

Що використовувати замість статичних методів? Ну, моя пропозиція - OOP. Чому б не спробувати?

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