В английской версии видел этот вопрос, но в русской версии не нашел. Часто некоторы
программисты используют 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.
Считаю, что это очень хорошая практика. И хотя бы ради такого способа объявлять приватный метод статическим не стоило бы.
Комментариев нет:
Отправить комментарий