Java: Когда сделать методы статичными v. экземпляров [закрытый]

Или можно просто звонить:

shutdown.exe -l -t 0

, Если Вы хотите простой способ. Я использую ExitWindowsEx сам.

33
задан 3 revs, 2 users 100% 24 October 2009 в 21:03
поделиться

14 ответов

Экземпляр, а не статический


В этом случае я думаю, что второй вариант явно лучше. Если подумать, любой метод может быть реализован как статический, если вы хотите передать ему объект, только этот кажется особым случаем, потому что другой параметр также является экземпляром.

Таким образом, наш поиск симметрии и абстракции несколько затрудняется тем, что приходится выбирать между двумя объектами экземпляра для оператора точки. Но если вы посмотрите на .method как на . затем оператор , это не проблема.

Кроме того, единственный способ создать цепочку функционального стиля - использовать атрибут, то есть метод экземпляра. Вероятно, вы хотите, чтобы thing.up.down.parent.next.distance (x) работал.

21
ответ дан 27 November 2019 в 18:04
поделиться

Основной причиной предпочтения метода экземпляра является полиморфизм. Статический метод не может быть переопределен подклассом, что означает, что вы не можете настроить реализацию на основе типа экземпляра. Возможно, это не применимо в вашем случае, но об этом стоит упомянуть.

Если расстояние между генами полностью не зависит от типа гена, я бы предпочел использовать отдельный служебный класс, чтобы сделать эту независимость более явной. Наличие метода geneDistance как части класса Gene подразумевает, что расстояние - это поведение, связанное с экземпляром гена.

0
ответ дан 27 November 2019 в 18:04
поделиться

Я бы выбрал второй подход. Я не вижу преимуществ в том, чтобы сделать метод статическим. Поскольку метод находится в классе Gene, делая его статическим, добавляется только один дополнительный параметр без дополнительного усиления. Если вам нужен класс утилиты, это совсем другое дело. Но на мой взгляд, обычно нет необходимости в классе util, если вы можете добавить метод в рассматриваемый класс.

0
ответ дан 27 November 2019 в 18:04
поделиться

Я думаю, что проблемная область должна давать ответ помимо общих стилистических и / или объектно-ориентированных соображений.

Например, я предполагаю, что в области генетического анализа понятия «ген» и «расстояние» довольно конкретны и не потребуют специализации посредством наследования. Если бы это было не так, можно было бы привести веские доводы в пользу выбора методов экземпляра.

Понятия «ген» и «расстояние» довольно конкретны и не требуют специализации посредством наследования. Если бы это было не так, можно было бы привести веские доводы в пользу выбора методов экземпляра.

Понятия «ген» и «расстояние» довольно конкретны и не требуют специализации посредством наследования. Если бы это было не так, можно было бы привести веские доводы в пользу выбора методов экземпляра.

0
ответ дан 27 November 2019 в 18:04
поделиться

Я бы сделал это методом экземпляра. Но это может быть связано с тем, что я понятия не имею о генах;)

Методы экземпляра могут быть переопределены подклассами, что значительно снижает сложность вашего кода (меньше необходимости в операторах if). Что произойдет в примере статического метода, если вы получите конкретный тип гена, для которого расстояние рассчитывается иначе? Добавить еще один статический метод? Если вам нужно обработать полиморфный список генов, вы

1
ответ дан 27 November 2019 в 18:04
поделиться

В этом конкретном случае я сделаю это методом интансирования. НО если у вас есть логический ответ, когда g0 имеет значение null, используйте ОБА (это происходит чаще, чем вы думаете).

Например, aString.startsWith () , если aString имеет значение null, вы можете думаю, что ЛОГИЧНО возвращать null (если вы думаете, что функция может быть NULL-TOLERATE). Это позволяет мне немного упростить мою программу, так как нет необходимости, чтобы aString проверяла null в клиентском коде.


final Stirng         aPrefix = "-";
final Vector aStrings = new Vector();
for(final String aString : aStrings) {
    if (MyString.startsWith(aString, aPrefix))
        aStrings.aStringadd();
}

вместо


final Stirng         aPrefix = "-";
final Vector aStrings = new Vector();
for(final String aString : aStrings) {
    if ((aString != null) && aString.startsWith(aPrefix))
        aStrings.aStringadd();
}

ПРИМЕЧАНИЕ: Это слишком упрощенный пример.

Просто мысль.

1
ответ дан 27 November 2019 в 18:04
поделиться

Вот мета-ответ и забавное упражнение: просмотрите несколько библиотечных классов Java SDK и посмотрите, сможете ли вы распределить общие черты между статическими методами в разных классах.

1
ответ дан 27 November 2019 в 18:04
поделиться

public static int geneDistance (Gene g0, Gene g1) будет частью отдельного служебного класса, такого как Collections и Arrays в Java тогда как public int geneDistance (Gene other) будет частью класса Gene . Учитывая, что у вас есть другие операции, такие как «обрезанные версии двух генов, поиск совпадений между генами, поиск совпадений между животными (которые содержат коллекции генов) и т. Д.», Я бы создал для них отдельный статический служебный класс, поскольку эти операции не имеют семантического смысла. что такое ген .

Если семантику «расстояния между генами» можно обернуть в ваш метод equals (Object o) , то вы можете использовать его там или в другом месте включите его в свою статическую утилиту.

3
ответ дан 27 November 2019 в 18:04
поделиться

Я предпочитаю вторую форму, то есть метод экземпляра, по следующим причинам:

  1. статические методы усложняют тестирование, потому что их нельзя заменить,
  2. статические методы более ориентированы на процедуры ( и, следовательно, менее объектно-ориентированный).

ИМО, статические методы подходят для служебных классов (например, StringUtils), но я предпочитаю не злоупотреблять ими.

8
ответ дан 27 November 2019 в 18:04
поделиться

Когда вы делаете метод статическим, это означает, что метод может вызываться без экземпляра класса. Это также означает, что метод не может получить доступ к переменным экземпляра, если ему не передана ссылка на объект.

Иногда имеет смысл сделать метод статическим, потому что метод связан с классом, но не с конкретным экземпляром класса. Например, все методы parseX, такие как Integer.parseInt (String s ). Это преобразует String в int , но не имеет ничего общего с конкретным экземпляром объекта Integer .

If, с другой стороны, рука, метод должен возвращать некоторые данные, которые уникальны для конкретного экземпляра объекта,

14
ответ дан 27 November 2019 в 18:04
поделиться

IMO не существует абсолютного «лучшего», но public int geneDistance (Gene other) стилистически больше похож на другие методы в Java (например, Object.equals, Comparable. compareTo), поэтому я бы пошел по этому пути.

8
ответ дан 27 November 2019 в 18:04
поделиться

​​Я хотел бы начать отвечать на ваш вопрос с нового: за что отвечает ваш класс, Джин? Возможно, вы слышали о «принципе единственной ответственности»: у класса должна быть только одна причина для изменения. Итак, я считаю, что если вы ответите на этот вопрос, вы сможете решить, как должно быть разработано ваше приложение. В данном случае я бы не стал использовать ни первый подход, ни второй. На мой взгляд, гораздо лучше определить новую ответственность и заключить ее в отдельный класс или может быть функцией.

2
ответ дан 27 November 2019 в 18:04
поделиться

Моя переформулировка ответа Чарльза:

Если рассматриваемый метод намерен каким-либо образом использовать состояние базового объекта , сделайте его методом экземпляра. В противном случае сделайте его статическим.

Это зависит от способа проектирования класса объекта.

В вашем случае alphazero, вероятно, int geneDistance (Gene g0, Gene g1) не ] действительно зависит от состояния экземпляра гена , который он вызывает. Я бы сделал этот метод статическим. И поместите его в служебный класс, например GeneUtils .

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

PS -> Причина, по которой я не стал бы помещать метод в класс Gene , заключается в том, что ген не должен отвечать за вычисление своего расстояния от другого гена. ; -)

7
ответ дан 27 November 2019 в 18:04
поделиться

I'll try to sum up some of the points already given here to which I agree.

Personally I don't think there is a "feels better" answer. Valid reasons do exist on why you don't wan't a utility class filled with static methods.

The short answer is that in an object oriented world you should use objects and all the good "stuff" that comes with them (encapsulation, polymorphism)

Polymorphism

If the method for calculating the distance between the genes varies, you should roughly (more likely a Strategy) have a Gene class per variation. Encapsulate what varies. Else you will end up with multiple ifs.

Open For Extension, Closed for Modification

That means that if a new method for calculating the distance between genes comes up down the line, you shouldn't modify existing code, but rather add new one. Else you risk breaking what's already there.

In this case you should add a new Gene class, not modify the code written in the #geneDistance

Tell Don't Ask

You should tell your objects what to do, not ask them for their state and make decisions for them. Suddenly you break the single responsibility principle since that's polymorphism.

Testability

Static methods may well be easy to test in isolation, but down the road you will make use of this static method in other classes. When it comes to testing that classes on isolation, you will have hard time doing it. Or rather not.

I'll let Misko have his saying which is more likely better than what I can come up with.

import junit.framework.Assert;

import org.junit.Test;

public class GeneTest
{
    public static abstract class Gene
    {
        public abstract int geneDistance(Gene other);
    }

    public static class GeneUtils
    {
        public static int geneDistance(Gene g0, Gene g1)
        {
            if( g0.equals(polymorphicGene) )
                return g0.geneDistance(g1);
            else if( g0.equals(oneDistanceGene) )
                return 1;
            else if( g0.equals(dummyGene) )
                return -1;
            else
                return 0;            
        }
    }


    private static Gene polymorphicGene = new Gene()
                                    {

                                        @Override
                                        public int geneDistance(Gene other) {
                                        return other.geneDistance(other);
                                        }
                                    };

    private static Gene zeroDistanceGene = new Gene() 
                                    {                                        
                                        @Override
                                        public int geneDistance(Gene other) {
                                        return 0;
                                        }
                                    };

    private static Gene oneDistanceGene = new Gene() 
                                    {                                        
                                        @Override
                                        public int geneDistance(Gene other) {
                                        return 1;
                                        }
                                    };

    private static Gene hardToTestOnIsolationGene = new Gene()
                                    {

                                        @Override
                                        public int geneDistance(Gene other) {
                                        return GeneUtils.geneDistance(this, other);
                                        }
                                    };

    private static Gene dummyGene = new Gene()
                                    {

                                        @Override
                                        public int geneDistance(Gene other) {
                                        return -1;
                                        }
                                    };                                    
    @Test
    public void testPolymorphism()
    {
        Assert.assertEquals(0, polymorphicGene.geneDistance(zeroDistanceGene));
        Assert.assertEquals(1, polymorphicGene.geneDistance(oneDistanceGene));
        Assert.assertEquals(-1, polymorphicGene.geneDistance(dummyGene));
    }

    @Test
    public void testTestability()
    {

        Assert.assertEquals(0, hardToTestOnIsolationGene.geneDistance(dummyGene));
        Assert.assertEquals(-1, polymorphicGene.geneDistance(dummyGene));
    }    

    @Test
    public void testOpenForExtensionClosedForModification()
    {

        Assert.assertEquals(0, GeneUtils.geneDistance(polymorphicGene, zeroDistanceGene));
        Assert.assertEquals(1, GeneUtils.geneDistance(oneDistanceGene, null));
        Assert.assertEquals(-1, GeneUtils.geneDistance(dummyGene, null));
    }    
}
2
ответ дан 27 November 2019 в 18:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: