Страницы

Поиск по вопросам

воскресенье, 24 ноября 2019 г.

Правильно делать приватные методы Java статическими или нет? Плюсы и минусы каждого варианта?


В английской версии видел этот вопрос, но в русской версии не нашел. Часто некоторы
программисты используют private static методы, чтобы показать что этот приватный мето
не использует никаких переменных и методов класса, другие наоборот против этого подхода так считают его не правильным использованием ООП (речь только о приватных методах класса, не использующих никаких переменных класса и других не статических методов). 

То есть, что правильнее по вашему использовать так 

   public class MyClass {      
      private static void func1() { // со статик
        ...
      }
   }


или так

   public class MyClass {      
      private void func1() { // без статик
        ...
      }
   }


?

Я говорил о тех методах, которые не используют (и не могут использовать) поля напрямую
например метод boolean isValid(T str), который вызывается в других методах класса для множества различных объектов, и которые нужны исключительно только для этого класса и выносить их в отдельный Utils класс нет смысла.

Как пример такого метода это hugeCapacity в ArrayList из Oracle JDK 8:

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}


P.S. Любые цитаты и ссылки на известных Java авторов очень помогут решить вопро
(скажем, я знаю, что в ArrayList из Oracle JDK, где авторы довольно известные Josh Bloch  и Neal Gafter, используется private static методы). Может вы знаете другие подтверждения той или иной точки зрения? 

То есть идеальный ответ, это ответ с цитатами на книги / статьи известных Java авторов или тех кто занимался теорией ООП или проектирования. 
    


Ответы

Ответ 1



Руководствуйтесь смыслом, и только им. Строение ваших классов должно отображать н техническую возможность сделать так или иначе (иногда экземплярные методы можно объявить статическими), а отношения между объектами в доменной области. Это и правда база всего ООП (а где ж ещё следовать ООП, если не в Джаве?). Я не могу привести цитату из умной книги по этому поводу. Но сама идея делать сигнатур метода зависимой не от его смысла, а от подробностей его конкретной имплементации кажетс мне грубым хаком. Даже если это внутренний, приватный метод. Если в публичных методах, предназначенных другим, мы пишем правильно, то почему в методах, предназначенных для себя, писать неправильно? Для отступления от правильного дизайна нужны веские причины. У ArrayList такие причин есть: он используется в миллионах проектов, и среди них есть критические по времен куски, и там выигрыш пары тактов играет серьёзную роль. Но для большинства классов, которые мы пишем, количество вызовов в наших программах не исчисляются десятками тысяч в секунду, и отступление от правильного дизайна вряд ли оправдано. Если метод относится к конкретному объекту, то объявляйте его экземплярным методо вне зависимости от того, обращается он к нестатическим полям и this или нет. Если мето общий для всего класса, и не имеет смысла в контексте отдельного экземпляра, объявляйте его статическим. Если метод вовсе не относится к классу, вынесите его во вспомогательный класс. Пример: оружие рыцаря — меч. Да, у всех рыцарей одинаковое оружие. Тем не менее метод, выдающий оружие — это очевидно экземплярный метод. Далее, рыцари не пользуются кинжалами. Поэтому геттер кинжала у рыцаря возвращает null. Это тоже экземплярный метод. class Knight : Warrior { private Weapon createMainWeapon() { return new Sword(); } private Dagger getDagger() { return null; } } Далее, количество рыцарей. Соответственно оно не имеет смысла в контексте одног рыцаря, значит, является статическим методом. class Knight : Warrior { static int numberOfKnights; public Knight() { numberOfKnights++; } public static int getNumber() { return numberOfKnights; } } Ну и наконец, метод, который выясняет, в порядке ли амуниция перед битвой, вообще не относится к сфере деятельности рыцаря. Пусть этим займётся оруженосец! class Squire { Knight master; public prepareForBattle() { ... } }

Ответ 2



Во-первых, для начала хорошо бы определиться, а нужен ли этому классу данный метод? Скажем, есть у нас класс машины и метод по переводу километров в мили. public class Car { private static double convertToMiles(double km){ return km*0.621371192; } } Очевидно, что этот метод вообще не нужен классу и его хорошо бы вынести в отдельный final Utils подобный класс, так как может быть использован много где. Renaud Waldura в "The Final Word on Final" пишет: Since a final method is only implemented in the declaring class, there is no need to dynamically dispatch a call to a final method, and static invocation can be used instead. The compiler can emit a direct call to the method, bypassing entirely the usual virtual method invocation procedure. Because of this, final methods are also candidates for inlining by a Just-In-Time compiler or a similar optimization tool. (Remember, private/static methods are already final, therefore always considered for this optimization.) Я лично делаю по возможности static, чтобы показать, что метод не зависит от состояни класса и никак на него не влияет. В IDE такой метод будет выделен italic шрифтом, что позволяет понять о его независимости от состояния класса, даже не заглядывая внутрь метода.

Ответ 3



Для более глубокого понимания добавлю исторический контекст вообще о статически методах. Некоторые исследователи вопроса вообще считают все подобные методы злом в ООП. Когда тема трудна для понимания, то один из лучших способов - обратиться к истории Java произошла от Smalltalk. Это знают все кто хоть один день потратил на его изучение В языке Smalltalk (с 1971 года) уже были статические методы - правда они там идут по названием "методы класса". Откуда же они появились там? Smalltalk имеет еще одного предка - Simula (с 1965 года). Оказывается и в Simula были такие методы - только там они идут под названием "свободный блок". Но в свою очередь кто "протащил" с язык Симула эти "свободные блоки"? А предок Симулы - Алгол. Потому что Симула изначально надмножество Алгола 60. Так что вот откуда ноги растут: а) Алгол procedure Absmax(a) Size:(n, m) Result:(y) Subscripts:(i, k); value n, m; array a; integer n, m, i, k; real y; comment The absolute greatest element of the matrix a, of size n by m is transferred to y, and the subscripts of this element to i and k; begin integer p, q; y := 0; i := k := 1; for p := 1 step 1 until n do for q := 1 step 1 until m do if abs(a[p, q]) > y then begin y := abs(a[p, q]); i := p; k := q end end Absmax б) Simula Begin Class Glyph; Virtual: Procedure print Is Procedure print; Begin End; Glyph Class Char (c); Character c; Begin Procedure print; OutChar(c); End; Glyph Class Line (elements); Ref (Glyph) Array elements; Begin Procedure print; Begin Integer i; For i:= 1 Step 1 Until UpperBound (elements, 1) Do elements (i).print; OutImage; End; End; Ref (Glyph) rg; Ref (Glyph) Array rgs (1 : 4); ! Main program; rgs (1):- New Char ('A'); rgs (2):- New Char ('b'); rgs (3):- New Char ('b'); rgs (4):- New Char ('a'); rg:- New Line (rgs); rg.print; End; Таким образом ООП изначально было надстройкой над императивным - поэтому совсем "выпилить статические методы не удастся. В институциональной экономике есть такое наблюдение приоритет/важность правила определяется только одним - стоимостью его изменения (или отмены). "Отменить" статические методы будет стоить человечеству столько человеко-лет, что видимо они с нами навсегда. Мы только можем уменьшить их использование в собственном коде с целью более удобной работы с объектами. Что касается именно приватных статических методов - к общим недостаткам статически методов добавляем еще и приватность. Очень редко встречал такие методы в коде. Сам не использую, так как стараюсь вообще минимизировать статические методы в коде и отношу себя к сторонникам идей Егора Бугаенко.

Ответ 4



Сразу обозначу ИМХО: метод не должен быть статическим и в посте стараюсь описат эту точку зрения. Каждый сам творит свой код. Может быть это актуально для оптимизации, но не для ООП. Получается это не метод, а процедура. Цитата из интервью David West: "Класс ничего не должен делать" Егор: Но в Java классы — не просто формочки для объектов. Мы туда помещаем методы… Дэвид: А зря! Егор: Вот в этом и мой вопрос! Дэвид: Ну, как я попытался сказать в книге, класс ничего не должен делать. В Smalltalk есть методы классов, но не надо их использовать. Их использование — возвращение к командному способу мышления. Вы берёте то, что должно быть ответственностью объектов, и по каким-то причинам пытаетесь запихнуть это всё в класс. И в итоге класс делает многое за объекты. интервью полностью Все сводиться к одному вопросу, почему этот метод должен принадлежать классу, а не объекту? Сейчас подумал, что эта цитата не в тему вопроса, но пусть останется. Я не совсем понимаю с какой целью делать приватный метод статическим. Если только для оптимизации. Если не брать в счет оптимизацию, то метод оперирует полями объекта (просто передан они будут как параметры). И тут можно вспомнить "чистый код". Чем меньше у метода параметров, тем проще он читается. Значит можно сделать его не статическим и использовать не параметры, а поля объекта. Если приватный метод не получает никаких параметров и не обращается к переменны объекта, то не совсем понимаю, что он будет делать. Update: Я говорил о тех методах, которые не используют (и не могут использовать) поля напрямую, например метод boolean isValid(T str), который вызывается в других методах класса для множества различных объектов, и которые нужны исключительно только для этого класса и выносить их в отдельный Utils класс нет смысла. Валидность объекта может определить сам объект и тут нужен "информационный эксперт и тогда суть дженерик метода уходит в каждый класс, т.е. вместо статического метода валидности любого объекта мы спросим сам объект валиден ли он.

Ответ 5



Возможно, это самое краткое пояснение смысла использования static методов. Статические методы следует применять в двух случаях. • Когда методу не требуется доступ к данным о состоянии объекта, поскольку вс необходимые параметры задаются явно (например, в методе Math.pow ()). • Когда методу требуется доступ лишь к статическим полям класса. Хорстманн, Кей С. Java. Библиотека профессионала, том 1. Основы. 10-е изд. стр.157

Ответ 6



Первым долгом хочу сказать это мое мнение это мой опыт !!! (Я думаю что вы знаете суть обычного и статического метода поэтому не пишу определение.) Статистический метод - это функциональный подход. В объектно-ориентированном проектирование это влияет на разработку то есть сопровождение сложно , мышление меняется на функциональность и так далее (общий ответ). Ну с точки зрения с памяти , обычный или статический метода нет потери почему: В памяти ".NET/Java" используется техника Flyweight (даже у этого техники есть паттерн но суть не в этом). Это техника экономит оперативной памяти (я не буду подробно объяснять технику) , и вот здесь обычный или статический метод не влияет никуда (с точки зрения памяти) , потом что каждого класса выделяется один объект(это технический имя) который методы содержатьс в этом объекте каждый экземпляр только содержит обычный Fields/Properties (изменчивый) и эти экземпляры ссылаются на этот объект , вот и краткие суть. (здесь подразумевается технический влияние). Хочу затронуть на один момент. Проблема в том что по-любому обычный или статически метод нельзя нагружать большой ответственность или большой объем кода (один из важных принципов). Я думаю что не надо так критически смотреть на эту тему. Не буду по философски сказку рассказывать. Ну вот разделил на две части (анализируйте). Ну и могу рекомендовать философскую книгу по этим темам "Object Thinking David West здесь подробно объясняется чистый объектно-ориентированное программирование/мышление архитектурное различие и такие темы как статический , обычные (методы , классы) и так далее.

Ответ 7



Нет неправильно. Точнее неправильно делать приватные методы класса статическими Технически конечно это можно делать, но по смыслу есть случаи когда это вредно и не нужно. Приведу пример: часто вижу, в том же самом Android, когда объявляется новый супер-пупе API, то при изучении исходников, выясняется, что просто сделали ранее приватный мето в классе публичным. То есть Google активно использует приватные нестатические метод в качестве способа управления версиями. Смысл простой, есть приватный метод, который скрыт внутри класса и активно используется нормальными публичными методами, таким образом метод проходит своеобразную обкатку в реальных условиях. Далее после изучения багтреков команда разработчиков решает вывести наружу метод: объявляется сигнатура метода как public и опля готово - прогеры получают в руки новый инструмент API. Считаю, что это очень хорошая практика. И хотя бы ради такого способа объявлять приватный метод статическим не стоило бы.

Комментариев нет:

Отправить комментарий