¿Cuál es la razón detrás de tener objetos de compañía en Scala?

¿Hay algún caso donde se necesite un objeto acompañante (singleton) para una clase? ¿Por qué querría crear una clase, decir Foo y también crear un objeto complementario para ella?

El objeto complementario básicamente proporciona un lugar donde uno puede poner métodos “estáticos”. Además, un objeto complementario, o módulo complementario, tiene acceso completo a los miembros de la clase, incluidos los privados.

Los objetos acompañantes son geniales para encapsular cosas como los métodos de fábrica. En lugar de tener que tener, por ejemplo, Foo y FooFactory todas partes, puede tener una clase con un objeto complementario que asum las responsabilidades de la fábrica.

Los objetos complementarios son útiles para almacenar el estado y los métodos que son comunes a todas las instancias de una clase, pero no usan métodos o campos estáticos . Usan métodos virtuales regulares que pueden ser anulados a través de la herencia. Scala realmente no tiene nada estático. Hay muchas maneras de usar esto, pero aquí hay un ejemplo simple.

 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 } 

Que produce esta salida:

 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 

… y es un buen lugar para almacenar métodos de fábrica estáticos (no ese DP) para clases acompañadas. Si nombras esos métodos de fábrica sobrecargados, aplica (/ /) podrás crear / inicializar tu clase

  1. sin ‘nuevo’ (realmente no tan importante)

  2. con diferentes conjuntos de parámetros posibles (compare con lo que Bloch escribe en Java efectivo sobre el constructor telescópico)

  3. con la capacidad de decidir qué clase derivada quieres crear en lugar de la clase abstracta (acompañada)

Código de ejemplo:

 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 

No llamaría al objeto / clase base AbstractXxxxx porque no se ve mal: como crear algo abstracto. Dale a esos nombres un significado real. Considere usar clases de casos inmutables, con menos métodos y selle la clase base abstracta.

Además de las cosas que Saem dijo en su respuesta , el comstackdor de Scala también busca conversiones implícitas de tipos en los objetos complementarios correspondientes (ya sea del origen o del objective), por lo que no es necesario importar las conversiones.

Sobre el motivo de los objetos singleton en general La progtwigción en Scala dice:

Como se mencionó en el Capítulo 1, una de las maneras en que Scala está más orientado a objetos que Java es que las clases en Scala no pueden tener miembros estáticos. En cambio, Scala tiene objetos singleton (p.65).

Siempre veo objetos complementarios como un puente para escribir código funcional y orientado a objetos en Scala. Muchas veces solo necesitamos funciones puras que toman algunas entradas y proporcionan un resultado de procesamiento. Poner esas funciones relevantes en el objeto complementario facilita la búsqueda y el uso, tanto para mí como para alguien que se basa en mi código.

Además, es una función proporcionada por el lenguaje para escribir el patrón singleton sin hacer nada. Esto es especialmente útil cuando necesita un singleton para encapsular un delegador durante toda la vida de JVM. Por ejemplo, escribir una biblioteca de cliente HTTP simple en Scala donde puede encapsular un delegador basado en la implementación subyacente de Java y permitir que los consumidores de su API vivan en un mundo puro.

Si define la clase y el objeto en el mismo archivo con el mismo nombre, se les conoce como clase acompañante y objeto. Scala no tiene estática como palabra clave JAVA, puede tomar como reemplazo de estática con clase acompañante y objeto en Scala.

Para obtener más información detallada, consulte la clase de artículo y la palabra clave de objeto en la progtwigción scala

Al principio, proporciona una separación clara de los métodos de métodos estáticos y no estáticos. También proporciona una forma simple de crear clases de singleton.

También puede heredar métodos de otras clases y / o rasgos, lo que no se puede hacer con los métodos estáticos de Java. Y se puede pasar como un parámetro.