В чем причина наличия сопутствующих объектов в Scala?

107

Есть ли случай, когда нужен сопутствующий объект (синглтон) для класса? Зачем мне, скажем, создавать класс, Fooа также создавать для него сопутствующий объект?

Рахул
источник
См. Также stackoverflow.com/a/9806136/736957, который является хорошей подборкой ответов здесь
laughedelic

Ответы:

82

Сопутствующий объект в основном предоставляет место, где можно разместить «статические» методы. Более того, сопутствующий объект или сопутствующий модуль имеет полный доступ к членам класса, включая частные.

Объекты-компаньоны отлично подходят для инкапсуляции таких вещей, как фабричные методы. Вместо того, чтобы иметь, например, Fooи FooFactoryвезде, вы можете иметь класс с объектом компаньона взять на фабричной обязанности.

Саэм
источник
61

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

abstract class AnimalCounter
{
    var animals = 0

    def name: String

    def count()
    {
        animals += 1
        println("%d %ss created so far".format(animals, name))
    }
}

abstract class Animal
{
    def companion: AnimalCounter
    companion.count()
}

object Dog extends AnimalCounter
{
    val name = "dog"
}

class Dog extends Animal
{
    def companion = Dog
}

object Cat extends AnimalCounter
{
    val name = "cat"
}

class Cat extends Animal
{
    def companion = Cat
}

Что производит этот вывод:

scala> new Dog
1 dogs created so far

scala> new Cat
1 cats created so far

scala> new Dog
2 dogs created so far

scala> new Cat
2 cats created so far
Крейг П. Мотлин
источник
1
аналогичную иллюстрацию также можно найти здесь: daily-scala.blogspot.sk/2009/09/companion-object.html
xhudik
30

... и это хорошее место для хранения статических фабричных методов (не DP) для сопровождаемых классов. Если вы назовете эти перегруженные фабричные методы apply (/ ... /), вы сможете создать / инициализировать свой класс

  1. без "нового" (не так уж и важно)

  2. с различными возможными наборами параметров (сравните с тем, что Блох пишет в Effective Java о телескопическом конструкторе)

  3. с возможностью решать, какой производный класс вы хотите создать вместо абстрактного (сопровождаемого)

Пример кода:

abstract class AbstractClass;
class RealThing(s: String) extends AbstractClass;
class AlternativeThing(i: Int) extends AbstractClass;
object AbstractClass {
  def apply(s: String) = {
    new RealThing(s)
  }
  def apply(i: Int) = {
    new AlternativeThing(i)
  }
}

// somewhere else you can
val vs = AbstractClass("asdf")  // gives you the RealThing wrapped over string
val vi = AbstractClass(123)  // gives you AlternativeThing wrapped over int

Я бы не стал называть объект / базовый класс AbstractXxxxx, потому что он неплохо выглядит: вроде создания чего-то абстрактного. Придайте этим именам реальный смысл. Рассмотрите возможность использования неизменяемых, безметодных, case-классов и запечатайте абстрактный базовый класс.

Шимон Яхим
источник
2
RealThingи AlternativeThingкласс должен иметь privateконструктор, чтобы заставить пользователя использовать AbstractClassфабрику has. class AlternativeThing private(i: Int) extends AbstractClass
metch
@ [Szymon Jachim] Абстрактный класс Scala не поддерживает множественное наследование. Так почему же компилятор позволяет это в вашем случае?
user2441441
19

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

О причине появления одноэлементных объектов в общем программировании на Scala говорится:

Как упоминалось в главе 1, одна из причин, по которой Scala более объектно-ориентирована, чем Java, состоит в том, что классы в Scala не могут иметь статических членов. Вместо этого в Scala есть одноэлементные объекты (стр. 65).

Фабиан Штег
источник
3

Я всегда рассматриваю сопутствующие объекты как мост для написания как функционального, так и объектно-ориентированного кода на Scala. Часто нам просто нужны чистые функции, которые принимают некоторый ввод и предоставляют результат обработки. Помещение этих соответствующих функций в сопутствующий объект упрощает поиск и использование для меня, а также для кого-то, построенного поверх моего кода.

Более того, это языковая функция для написания одноэлементного шаблона без каких-либо действий. Это особенно полезно, когда вам нужен синглтон для инкапсуляции делегатора на время существования JVM. Например, написание простой клиентской библиотеки HTTP на Scala, в которой вы можете инкапсулировать базовый делегатор на основе реализации Java и позволить потребителям вашего API жить в чистом мире.

Гаурав Абби
источник
0

Если вы определяете класс и объект в одном файле с тем же именем, они называются сопутствующим классом и объектом. В Scala нет static в качестве ключевого слова JAVA. Вы можете заменить static на класс-компаньон и объект в Scala.

Для получения более подробной информации, пожалуйста, проверьте класс статьи и ключевое слово объекта в программировании на Scala.

FOD
источник
-1

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

Он также может наследовать методы от других классов и / или признаков, что невозможно сделать с помощью статических методов Java. Его можно передать как параметр.

vipin
источник