Почему одноэлементные объекты более объектно-ориентированы?

В статье "Программирование в Scala: подробное пошаговое руководство" автор сказал:

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

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

7 ответов

Решение

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

Статические методы класса не являются методами объекта, это означает, что:

  1. Статические члены не могут быть унаследованы от родительского класса / признака
  2. Статические члены не могут быть использованы для реализации интерфейса
  3. Статические члены класса не могут быть переданы в качестве аргумента какой-либо функции

    (и из-за вышеуказанных пунктов...)

  4. Статические члены не могут быть переопределены
  5. Статические члены не могут быть полиморфными

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

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


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

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

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

Я не могу сделать это в Java только с помощью статических классов - это просто сахар по сравнению с одноэлементным шаблоном Java с getInstance это позволяет (по крайней мере) более хорошие пространства имен / стабильные идентификаторы и скрывает различие.

Подсказка: это называется объектно- ориентированным программированием.

Шутки в сторону.

Может быть, я упускаю что-то принципиально важное, но я не понимаю, в чем суть суеты: объекты более объектно-ориентированы, чем не-объекты, потому что они являются объектами. Это действительно нуждается в объяснении?

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

Альтернативой наличию одноэлементных объектов было бы создание классов самими объектами, как, например, Ruby, Python, Smalltalk, Newspeak.

Для статических членов нет объекта. Класс действительно просто является пространством имен.

В синглтоне всегда есть хотя бы один объект.

Честно говоря, это расщепление волосков.

Он более объектно-ориентирован в том смысле, что для данного класса Scala каждый вызов метода является вызовом метода для этого объекта. В Java статические методы не взаимодействуют с состоянием объекта.

На самом деле, учитывая объект a класса A статическим методом m()звонить считается плохой практикой a.m(), Вместо этого рекомендуется позвонить A.m() (Я верю, что "Затмение" предупредит вас). Статические методы Java не могут быть переопределены, они могут быть просто скрыты другим методом:

class A {
    public static void m() {
        System.out.println("m from A");
    }
}
public class B extends A {
    public static void m() {
        System.out.println("m from B");
    }
    public static void main(String[] args) {
        A a = new B();
        a.m();
    }
}

Что будет a.m() Распечатать?

В Scala вы вставляете статические методы в сопутствующие объекты A и B, и цель будет более ясной, как если бы вы явно ссылались на спутника A или B.

Добавление того же примера в Scala:

class A
object A { 
  def m() = println("m from A") 
}
class B extends A
object B { 
  def m() = println("m from B")
  def main(args: Array[String]) {
    val a = new B
    A.m() // cannot call a.m()
  }
}

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

Это действительно маркетинговая вещь. Рассмотрим два примера:

class foo
   static const int bar = 42;
end class

class superfoo
    Integer bar = ConstInteger.new(42);
end class

Теперь, какие здесь наблюдаемые различия?

  • на хорошем языке созданное дополнительное хранилище остается тем же.
  • Foo.bar и Superfoo.bar имеют абсолютно одинаковые подписи, доступ и т. Д.
  • Superfoo.bar может быть размещен по-разному, но это деталь реализации

Это напоминает мне о религиозных войнах 20 лет назад по поводу того, были ли C++ или Java "действительно" объектно-ориентированными, поскольку в конце концов оба представленных примитивных типа не являются "настоящими" объектами - так, например, вы не можете наследовать от int но может от Integer,

Другие вопросы по тегам