Почему статические методы не считаются хорошей практикой объектно-ориентированного программирования?

Я читаю Программирование Scala. В начале главы 4 автор отмечает, что Java поддерживает статические методы, которые являются «не очень чистыми объектно-ориентированными концепциями». Почему это так?


person Mike    schedule 23.10.2010    source источник
comment
Я не уверен, что не очень чистый должен быть немедленно связан с плохой практикой.   -  person mellowsoon    schedule 23.10.2010
comment
Неплохая практика. Просто нехорошая практика, по мнению автора.   -  person Mike    schedule 23.10.2010
comment
Автор не аргументирует?   -  person    schedule 25.10.2010
comment
Никто. Это сбивало с толку. Но теперь это имеет смысл.   -  person Mike    schedule 25.10.2010
comment
Суть проблемы: статические вещи не могут быть полиморфными.   -  person Dávid Horváth    schedule 27.06.2018


Ответы (7)


Одна из причин, по которой статические методы не являются объектно-ориентированными, до сих пор не упоминалась, заключается в том, что интерфейсы и абстрактные классы определяют только нестатические методы. Таким образом, статические методы не очень хорошо подходят для наследования.

Также обратите внимание, что статические методы не имеют доступа к "super", что означает, что статические методы нельзя переопределить в каком-либо реальном смысле. На самом деле, их вообще нельзя переопределить, только скрыть. Попробуй это:

public class Test {
    public static int returnValue() {
        return 0;
    }

    public static void main(String[] arg) {
        System.out.println(Test.returnValue());
        System.out.println(Test2.returnValue());
        Test x = new Test2();
        System.out.println(x.returnValue());
    }
}


public class Test2 extends Test {
    public static int returnValue() {
        return 1;
    }
}

Когда вы запустите это, вы не получите того, что ожидаете. Test.returnValue() дает то, что вы ожидаете. Test2.returnValue() скрывает одноименный метод в суперклассе (он не переопределяет его), и он дает то, что вы ожидаете.

Можно было бы наивно ожидать, что "нестатический" вызов статического метода будет использовать полиморфизм. Это не так. В каком бы классе ни была объявлена ​​переменная, она используется для поиска метода. Это плохой тон, потому что кто-то может ожидать, что код будет делать что-то отличное от того, что он делает на самом деле.

Это не означает: «Не используйте статические методы!» Это означает, что вы должны зарезервировать использование статических методов для тех случаев, когда вы действительно хотите, чтобы объект класса владел методом, а не просто как ленивый способ создания синглтона.

person Eddie    schedule 23.10.2010
comment
Этот ответ, вероятно, имеет наибольший смысл из того, что я видел до сих пор. Нарушение одной из концепций троицы, безусловно, идет вразрез с зерном. - person Mike; 23.10.2010
comment
Не то чтобы я оспаривал это, но пример, который вы показываете, относится только к Java, верно? IIRC, Java - единственный язык OO (с которым я столкнулся), который позволяет вызывать статические функции через экземпляр класса. - person Jeff Mercado; 23.10.2010
comment
@Jeff: VB.NET также допускает такое бессмысленное поведение. - person Adam Robinson; 23.10.2010
comment
@Jeff: C ++ и Python позволяют это. Это не так бессмысленно, как вы могли бы подумать, хотя, конечно, иногда это сбивает с толку (как и любая функция). - person ; 25.10.2010

Объектная ориентация связана с тремя вещами:

  • обмен сообщениями,
  • локальное сохранение и защита и сокрытие процесса состояния, а также
  • крайне позднее связывание всех вещей.

Из этих трех наиболее важным является обмен сообщениями.

Статические методы нарушают как минимум обмен сообщениями и позднее связывание.

Идея обмена сообщениями означает, что в ОО вычисления выполняются сетями автономных объектов, которые отправляют сообщения друг другу. Отправка сообщения является единственным способом связи/вычислений.

Статические методы этого не делают. Они не связаны ни с одним объектом. На самом деле они совсем не являются методами, согласно обычному определению. На самом деле это просто процедуры. Практически нет разницы между статическим методом Java Foo.bar и подпрограммой BASIC FOO_BAR.

Что касается позднего связывания: более современное название для этого — динамическая отправка. Статические методы тоже нарушают это, даже в самом их названии: статические методы.

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

Вы также можете выполнять каждый объект параллельно в своем собственном процессе, поскольку они взаимодействуют только посредством обмена сообщениями, что обеспечивает некоторый тривиальный параллелизм. (По сути, как и Актеры, что не должно вызывать удивления, поскольку Карл Хьюитт создал Модель Актера на основе Smalltalk-71, а Алан Кей создал Smalltalk-71 частично на основе PLANNER, который, в свою очередь, был созданный Карлом Хьюиттом. Тесная связь между акторами и объектами далеко не случайна, на самом деле они по сути одно и то же.) Опять же, статика (как статические методы, так и особенно статическое состояние) ломаются это хорошее свойство.

person Jörg W Mittag    schedule 23.10.2010
comment
Спасибо за ваш очень содержательный ответ. - person BillMan; 24.02.2021

Не путайте «не очень чистые концепции объектно-ориентированного программирования» с «плохой практикой». Быть «чистым ОО» — это не панацея, которую вы должны пытаться достичь. Тот факт, что статические методы не принимают переменную экземпляра в качестве параметра, не означает, что они бесполезны. Некоторые вещи просто не поддаются объектам, и их не следует загонять в эту форму только ради «чистоты».

Некоторые люди думают, что вещи должны быть «чистыми», и поэтому все «нечистое» — плохая практика. В действительности, плохой практикой является просто делать вещи, которые сбивают с толку, их трудно поддерживать, трудно использовать и т. д. Создание статических методов, которые принимают экземпляр, плохая практика, потому что любой метод, который принимает экземпляр, вероятно, должен быть метод экземпляра. С другой стороны, такие вещи, как служебные и фабричные функции, обычно не принимают экземпляр, поэтому они должны быть статическими.

Если вам интересно, почему они не являются «чистым ООП», это потому, что они не являются методами экземпляра. В «чистом» объектно-ориентированном языке все было бы объектом, а все функции были бы методами экземпляра. Конечно, это не очень полезно все время. Например, рассмотрим метод Math.atan2. Он принимает два числа и не требует никакого состояния. Какой объект вы могли бы сделать методом of? В «чистом» объектно-ориентированном языке Math может быть объектом (вероятно, синглтоном), а atan2 будет методом экземпляра, но, поскольку функция фактически не использует никакого состояния в объекте Math, она также не является Концепция «чистого ОО».

person Gabe    schedule 23.10.2010
comment
Имейте в виду, что я никогда не говорил, что это плохая практика, поэтому на мой вопрос не было ответа. ;) - person Mike; 23.10.2010
comment
Истинный. С другой стороны, я видел слишком много кода, где все одноэлементно и все статично. Такой код обычно труднее модифицировать, труднее расширить, труднее переделать, чтобы сделать что-то, для чего он изначально не предназначался. Тем не менее, слишком много людей слишком догматичны по этому поводу. - person Eddie; 23.10.2010
comment
На самом деле, функция atan2 измеряет в радианах угол одной точки с положительной осью x. Другими словами, он не должен принимать два числовых аргумента, в первую очередь, он должен принимать один точечный аргумент. Что, в терминах ООП, можно смоделировать как метод для точечного объекта. - person Jörg W Mittag; 23.10.2010
comment
Йорг: А как насчет функций stdev и average? Должны ли это быть методы Array? Или они должны быть методами экземпляра своего собственного класса (Stats), который содержит все числа, так что вам нужно преобразовать Array в Stats, чтобы вы могли их усреднить? Или это должны быть статические методы, которым вы просто передаете массив чисел? - person Gabe; 23.10.2010
comment
Я полностью согласен. Очень много служебных функций просто не имеют в своей природе объектно-ориентированного программирования. Вы можете впихнуть их в объектно-ориентированный язык, но все, что вы делаете, это добавляете неэффективности. - person Loren Pechtel; 25.10.2010

Статические методы вызывают тесную связь, что является нарушением хорошего объектно-ориентированного проектирования. Тесной связи вызывающего кода и кода внутри статического метода нельзя избежать с помощью инверсии зависимостей, поскольку статические методы по своей сути не поддерживают методы объектно-ориентированного проектирования, такие как наследование и полиморфизм.

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

person Ilia Anastassov    schedule 28.09.2017
comment
вкратце - статические методы - это инструмент ООП для процедурного программирования - person ikirachen; 30.08.2018

Статические методы не считаются хорошей практикой OO по следующим причинам:

1) Предотвращает повторное использование:

Статические методы нельзя переопределить. Его нельзя использовать в интерфейсе.

2) Срок службы объекта очень велик:

Статические методы остаются в памяти в течение логарифмического времени, и их сборка мусора занимает много времени. Разработчики не имеют контроля над уничтожением или созданием статических переменных. Чрезмерное использование статических переменных может привести к переполнению памяти.

3) И еще несколько моментов:

Он не соблюдает инкапсуляцию, потому что объект не полностью контролирует свое состояние. Он не следует таким понятиям, как инверсия управления, слабая связь, внедрение зависимостей и т. д.

person Gul Ershad    schedule 21.10.2017

Статические методы не являются такими чистыми объектно-ориентированными концепциями, потому что их можно вызывать без фактического связывания объекта с ними. Вы используете сам класс. Вы вызываете их вот так Classname.method(...);

person Luis Miguel Serrano    schedule 23.10.2010
comment
Что, если я использую что-то вроде Ruby, который поддерживает классы как объекты и статический вызов? Фактически объект будет связан со статическим вызовом. - person Mike; 23.10.2010
comment
Ну, я не уверен, насколько автор был связан с Java, когда сказал, что он сделал, но дело в том, что даже в Java есть объекты, которые создаются и управляются для представления самих классов, так что это все немного обсуждаемо, до некоторой степени. Однако простая идея, что у вас есть статический метод main и статические методы, которые вы можете вызывать без каких-либо объектов, немного противоречит парадигме ООП. - person Luis Miguel Serrano; 23.10.2010

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

--Ваше здоровье

person Koteswara sarma    schedule 23.10.2010