"Статичність" як семантична підказка про безгромадянськість?


11

Нещодавно я здійснив рефакторинг середнього розміру проекту на Java, щоб повернутися назад та додати тестові одиниці. Коли я зрозумів, який біль викликати знущання над одинаками та статикою, я нарешті «дістав» те, що читав про них увесь цей час. (Я один з тих людей, яким потрібно вчитися на досвіді. Ну добре.)

Отже, тепер, коли я використовую Spring для створення об’єктів і обведення їх навколо, я позбавляюся staticключових слів ліворуч та праворуч. (Якщо я можу потенційно захотіти знущатися над цим, це насправді не є статичним у тому ж сенсі, що Math.abs (), правда?) Справа в тому, що я ввійшов у звичку використовувати, staticщоб позначити, що метод не покладається на будь-який стан об'єкта. Наприклад:

//Before
import com.thirdparty.ThirdPartyLibrary.Thingy;
public class ThirdPartyLibraryWrapper {
    public static Thingy newThingy(InputType input) {
         new Thingy.Builder().withInput(input).alwaysFrobnicate().build();
    }
}

//called as...
ThirdPartyLibraryWrapper.newThingy(input);
//After
public class ThirdPartyFactory {
    public Thingy newThingy(InputType input) {
         new Thingy.Builder().withInput(input).alwaysFrobnicate().build();
    }
}

//called as...
thirdPartyFactoryInstance.newThingy(input);

Отже, ось, де це стає чуйним. Мені сподобався старий спосіб, оскільки велика літера сказала мені, що так само, як і Math.sin (x), ThirdPartyLibraryWrapper.newThingy (x) робив те саме, що і те саме щоразу. Немає стану об'єкта, який би міг змінити те, як об’єкт робить те, про що я його прошу. Ось кілька можливих відповідей, які я розглядаю.

  • Ніхто більше не відчуває себе таким чином, тож зі мною щось не так. Можливо, я просто насправді не усвідомлював OO способу ведення справ! Можливо, я пишу на Java, але думаю в FORTRAN або щось подібне. (Що було б вражаючим, оскільки я ніколи не писав FORTRAN.)
  • Можливо, я використовую статичність як свого роду проксі для незмінності для міркувань про код. Якщо говорити, які підказки я повинен мати у своєму коді для того, щоб хтось прийшов, щоб підтримати його, щоб знати, що таке стан, а що ні?
  • Можливо, це повинно вийти безкоштовно, якщо я оберу хороші метафори об’єктів? наприклад thingyWrapper, не звучить так, що він має стан незалежного від загорнутого, Thingyякий може сам змінюватися. Так само thingyFactoryзвучить, як це має бути незмінним, але може мати різні стратегії, які вибираються серед створення.

Відповіді:


12

Мені сподобався старий спосіб, оскільки велика літера сказала мені, що так само, як і Math.sin (x), ThirdPartyLibraryWrapper.newThingy (x) робив те саме, що і те саме щоразу. Немає стану об'єкта, який би міг змінити те, як об’єкт робить те, про що я його прошу.

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

Розглянемо наступне:

public static class Logger
{
    public static int LogLevel { get; set; }

    public static void Log(string message, int logLevel)
    {
        if (logLevel >= LogLevel)
        {
            // logs the message, but only if it is important enough.
        }
    }
}

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


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

1
Зазвичай такі очікування містяться в документації щодо методу; те ж саме стосується безпеки ниток.
Роберт Харві

5

На мою думку, те, що ви говорите, - всі статичні функції, які є нульовими, - це хороший спосіб написання коду в більшості випадків, але я не вірю, що, дивлячись на статичну функцію, ви повинні автоматично припускати, що вона не має побічних ефектів . Ситуація може бути більш складною; візьмемо для прикладу функцію, Class.forName(String)яка видається без стану, але вона фактично завантажує клас у пам'ять і врешті-решт інстанціює статичні поля / запустить статичний ініціалізатор; це приклад ідентифікаційної функції (можливі дзвінки після першого не мають значення), але це не є чистою функцією (не можна сказати, що вона не має побічних ефектів). Це також вдалий вибір, але можуть бути випадки, коли три різних виклику однієї і тієї ж функції дають три різні результати; наприклад, якщо ви телефонуєтеThread.currentThread() у багатопотоковому додатку немає гарантії, що ви будете отримувати ту саму нитку кожного разу.

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

Правильне рішення - документувати (наприклад, Javadoc); також, з назви функції та того, що вона іноді робить, можна зробити висновок, що статична функція є чистою функцією. Наприклад, немає причин хтось вірити, що Assert.assertTrue(boolean)з JUnit десь зміниться якийсь стан. З іншого боку, коли така функція System.clearProperty(String)викликається, цілком очевидно, що будуть побічні ефекти.


Яка різниця між "несильним" та "без громадянства"?
Pacerier

@Pacerier Різниці не повинно бути.
m3th0dman

4

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

Ви можете зробити їх статичними. FxCop у світі C # підштовхне вас до того, щоб зробити статичні речі, що не мають змінних еталонних членів. Це правильно робити (як правило).

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

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


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

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