Я читаю Программирование Scala. В начале главы 4 автор отмечает, что Java поддерживает статические методы, которые являются «не очень чистыми объектно-ориентированными концепциями». Почему это так?
Почему статические методы не считаются хорошей практикой объектно-ориентированного программирования?
Ответы (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()
скрывает одноименный метод в суперклассе (он не переопределяет его), и он дает то, что вы ожидаете.
Можно было бы наивно ожидать, что "нестатический" вызов статического метода будет использовать полиморфизм. Это не так. В каком бы классе ни была объявлена переменная, она используется для поиска метода. Это плохой тон, потому что кто-то может ожидать, что код будет делать что-то отличное от того, что он делает на самом деле.
Это не означает: «Не используйте статические методы!» Это означает, что вы должны зарезервировать использование статических методов для тех случаев, когда вы действительно хотите, чтобы объект класса владел методом, а не просто как ленивый способ создания синглтона.
Объектная ориентация связана с тремя вещами:
- обмен сообщениями,
- локальное сохранение и защита и сокрытие процесса состояния, а также
- крайне позднее связывание всех вещей.
Из этих трех наиболее важным является обмен сообщениями.
Статические методы нарушают как минимум обмен сообщениями и позднее связывание.
Идея обмена сообщениями означает, что в ОО вычисления выполняются сетями автономных объектов, которые отправляют сообщения друг другу. Отправка сообщения является единственным способом связи/вычислений.
Статические методы этого не делают. Они не связаны ни с одним объектом. На самом деле они совсем не являются методами, согласно обычному определению. На самом деле это просто процедуры. Практически нет разницы между статическим методом Java Foo.bar
и подпрограммой BASIC FOO_BAR
.
Что касается позднего связывания: более современное название для этого — динамическая отправка. Статические методы тоже нарушают это, даже в самом их названии: статические методы.
Статические методы нарушают некоторые очень хорошие свойства объектной ориентации. Например, объектно-ориентированные системы автоматически защищены от возможностей, а объекты действуют как возможности. Статические методы (или действительно любые статические методы, будь то статическое состояние или статические методы) нарушают это свойство.
Вы также можете выполнять каждый объект параллельно в своем собственном процессе, поскольку они взаимодействуют только посредством обмена сообщениями, что обеспечивает некоторый тривиальный параллелизм. (По сути, как и Актеры, что не должно вызывать удивления, поскольку Карл Хьюитт создал Модель Актера на основе Smalltalk-71, а Алан Кей создал Smalltalk-71 частично на основе PLANNER, который, в свою очередь, был созданный Карлом Хьюиттом. Тесная связь между акторами и объектами далеко не случайна, на самом деле они по сути одно и то же.) Опять же, статика (как статические методы, так и особенно статическое состояние) ломаются это хорошее свойство.
Не путайте «не очень чистые концепции объектно-ориентированного программирования» с «плохой практикой». Быть «чистым ОО» — это не панацея, которую вы должны пытаться достичь. Тот факт, что статические методы не принимают переменную экземпляра в качестве параметра, не означает, что они бесполезны. Некоторые вещи просто не поддаются объектам, и их не следует загонять в эту форму только ради «чистоты».
Некоторые люди думают, что вещи должны быть «чистыми», и поэтому все «нечистое» — плохая практика. В действительности, плохой практикой является просто делать вещи, которые сбивают с толку, их трудно поддерживать, трудно использовать и т. д. Создание статических методов, которые принимают экземпляр, плохая практика, потому что любой метод, который принимает экземпляр, вероятно, должен быть метод экземпляра. С другой стороны, такие вещи, как служебные и фабричные функции, обычно не принимают экземпляр, поэтому они должны быть статическими.
Если вам интересно, почему они не являются «чистым ООП», это потому, что они не являются методами экземпляра. В «чистом» объектно-ориентированном языке все было бы объектом, а все функции были бы методами экземпляра. Конечно, это не очень полезно все время. Например, рассмотрим метод Math.atan2
. Он принимает два числа и не требует никакого состояния. Какой объект вы могли бы сделать методом of? В «чистом» объектно-ориентированном языке Math
может быть объектом (вероятно, синглтоном), а atan2
будет методом экземпляра, но, поскольку функция фактически не использует никакого состояния в объекте Math
, она также не является Концепция «чистого ОО».
atan2
измеряет в радианах угол одной точки с положительной осью x. Другими словами, он не должен принимать два числовых аргумента, в первую очередь, он должен принимать один точечный аргумент. Что, в терминах ООП, можно смоделировать как метод для точечного объекта.
- person Jörg W Mittag; 23.10.2010
stdev
и average
? Должны ли это быть методы Array
? Или они должны быть методами экземпляра своего собственного класса (Stats
), который содержит все числа, так что вам нужно преобразовать Array
в Stats
, чтобы вы могли их усреднить? Или это должны быть статические методы, которым вы просто передаете массив чисел?
- person Gabe; 23.10.2010
Статические методы вызывают тесную связь, что является нарушением хорошего объектно-ориентированного проектирования. Тесной связи вызывающего кода и кода внутри статического метода нельзя избежать с помощью инверсии зависимостей, поскольку статические методы по своей сути не поддерживают методы объектно-ориентированного проектирования, такие как наследование и полиморфизм.
Кроме того, статические методы трудно тестировать из-за этих сильно связанных зависимостей, которые часто приводят к сторонней инфраструктуре, от которой зависит код, например к базе данных, и это очень затрудняет изменение поведения без фактического входа и изменения код.
Статические методы не считаются хорошей практикой OO по следующим причинам:
1) Предотвращает повторное использование:
Статические методы нельзя переопределить. Его нельзя использовать в интерфейсе.
2) Срок службы объекта очень велик:
Статические методы остаются в памяти в течение логарифмического времени, и их сборка мусора занимает много времени. Разработчики не имеют контроля над уничтожением или созданием статических переменных. Чрезмерное использование статических переменных может привести к переполнению памяти.
3) И еще несколько моментов:
Он не соблюдает инкапсуляцию, потому что объект не полностью контролирует свое состояние. Он не следует таким понятиям, как инверсия управления, слабая связь, внедрение зависимостей и т. д.
Статические методы не являются такими чистыми объектно-ориентированными концепциями, потому что их можно вызывать без фактического связывания объекта с ними. Вы используете сам класс. Вы вызываете их вот так Classname.method(...);
Концепция ООП говорит об управлении/доступе к данным из объекта, но статические методы не нужно вызывать с использованием объекта, и они принадлежат классу, а не объекту.
--Ваше здоровье