Existe um caso em que um objeto companheiro (singleton) para uma classe é necessário? Por que eu iria querer criar uma classe, digamos, Foo
e também criar um objeto companheiro para ela?
Existe um caso em que um objeto companheiro (singleton) para uma classe é necessário? Por que eu iria querer criar uma classe, digamos, Foo
e também criar um objeto companheiro para ela?
Respostas:
O objeto companheiro basicamente fornece um local onde se pode colocar métodos "do tipo estático". Além disso, um objeto companheiro, ou módulo companheiro, tem acesso total aos membros da classe, incluindo os particulares.
Os objetos companheiros são ótimos para encapsular coisas como métodos de fábrica. Em vez de ter que ter, por exemplo, Foo
e em FooFactory
todos os lugares, você pode fazer com que uma classe com um objeto companheiro assuma as responsabilidades da fábrica.
Os objetos complementares são úteis para armazenar estados e métodos comuns a todas as instâncias de uma classe, mas não usam métodos ou campos estáticos . Eles usam métodos virtuais regulares que podem ser substituídos por herança. Scala realmente não tem nada estático. Existem muitas maneiras de usar isso, mas aqui está um exemplo simples.
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
}
O que produz esta saída:
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
... e é um bom lugar para armazenar métodos de fábrica estáticos (não aquele DP) para classes acompanhadas. Se você nomear esses métodos de fábrica sobrecarregados como (/ ... /), você será capaz de criar / inicializar sua classe
sem 'novo' (não é tão importante)
com diferentes conjuntos de parâmetros possíveis (compare com o que Bloch escreve em Effective Java sobre construtor telescópico)
com a capacidade de decidir qual classe derivada você deseja criar em vez da abstrata (acompanhada)
Código de exemplo:
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
Eu não chamaria o objeto / classe base de AbstractXxxxx porque não parece ruim: como criar algo abstrato. Dê a esses nomes um significado real. Considere o uso de classes de caso imutáveis, sem método, e sele a classe base abstrata.
RealThing
e a AlternativeThing
classe deve ter um private
construtor para forçar o usuário a usar a AbstractClass
fábrica. class AlternativeThing private(i: Int) extends AbstractClass
Além das coisas que Saem disse em sua resposta , o compilador Scala também procura conversões implícitas de tipos nos objetos complementares correspondentes (da origem ou do destino), portanto, as conversões não precisam ser importadas.
Sobre a razão para objetos singleton em geral, a programação em Scala diz:
Conforme mencionado no Capítulo 1, uma maneira pela qual Scala é mais orientado a objetos do que Java é que as classes em Scala não podem ter membros estáticos. Em vez disso, Scala possui objetos singleton (p. 65).
Sempre vejo os objetos complementares como uma ponte para escrever código funcional e orientado a objetos em Scala. Muitas vezes, precisamos apenas de funções puras que recebem alguma entrada e fornecem um resultado de processamento. Colocar essas funções relevantes no objeto complementar facilita a pesquisa e o uso, tanto para mim quanto para quem está construindo sobre meu código.
Além disso, é um recurso fornecido pela linguagem para escrever o padrão singleton sem fazer nada. Isso é especialmente útil quando você precisa de um singleton para encapsular um delegador para a vida da JVM. Por exemplo, escrever uma biblioteca cliente HTTP simples em Scala onde você pode encapsular um delegador baseado em implementação Java subjacente e permitir que os consumidores de sua API vivam em um mundo puro.
Se você definir classe e objeto no mesmo arquivo com o mesmo nome, eles são conhecidos como classe e objeto complementares. Scala não tem static como palavra-chave JAVA, você pode tomar como substituição de static com classe companion e objeto em Scala.
Para obter informações mais detalhadas, verifique a classe do artigo e a palavra-chave do objeto em programação scala
A princípio, ele fornece uma separação clara dos métodos de métodos estáticos e não estáticos. Também fornece uma maneira simples de criar uma classe de singleton.
Ele também pode herdar métodos de outras classes e / ou características, o que não pode ser feito com métodos estáticos Java e pode ser passado como um parâmetro.