Construtor privado e protegido em Scala

109

Estou curioso sobre o impacto de não ter um construtor primário explícito no Scala, apenas o conteúdo do corpo da classe.

Em particular, eu suspeito que o padrão de construtor privado ou protegido, ou seja, a construção de controle por meio do objeto companheiro ou de outra classe ou métodos de objeto, pode não ter uma implementação óbvia.

Estou errado? Se sim, como isso é feito?

Don Mackenzie
fonte
Você poderia ter um singleton Scala (com a palavra-chave object, isto é) e definir sua classe como privada dentro desse singleton e ter métodos do singleton para construir seus objetos.
Paggas
@Paggas, infelizmente, quando você retorna uma instância de uma classe marcada como privada fora de seu escopo, ela não compila, mesmo quando retornada de um método de seu objeto companheiro de escopo.
Don Mackenzie
Isso é feito profusamente em todo o código-fonte do Scalaz. O conceito também é conhecido como um tipo de dados algébrico abstrato .
Tony Morris

Respostas:

190

Você pode declarar o construtor padrão como privado / protegido inserindo a palavra-chave apropriada entre o nome da classe e a lista de parâmetros, assim:

class Foo private () { 
  /* class body goes here... */
}
Aleksander Kmetec
fonte
Obrigado Aleksander, Você pode me dizer se isso é apresentado em um dos livros do scala ou na especificação do idioma? Lamento, mas ainda não consigo votar positivamente.
Don Mackenzie
Acabei de dar uma olhada na explicação dos construtores de "Programming Scala" (páginas 92-95) e não vejo isso mencionado lá. Na verdade, encontrei a resposta para sua pergunta em um antigo changelog, mas nunca vi isso mencionado em nenhum outro lugar antes. Link: scala-lang.org/node/43#2.4.0
Aleksander Kmetec
18
Pag. 414 de "Programação em Scala". Página 97 da Scala de programação de Wampler. Página 60 da Scala de programação do Subramaniam. Não tenho um PDF do Iniciante Scala comigo agora para conferir.
Daniel C. Sobral
Oh, eu vejo agora na página 97. Obrigado.
Aleksander Kmetec
1
Obrigado pela pesquisa adicional, eu tenho o livro de Wampler, mas apenas no meu telefone e claramente não o li completamente, mas descobri que ele complementa o livro de Odersky surpreendentemente bem.
Don Mackenzie
64

A resposta de Aleksander está correta, mas a programação em Scala oferece uma alternativa adicional:

sealed trait Foo {
 // interface
}

object Foo {
  def apply(...): Foo = // public constructor

  private class FooImpl(...) extends Foo { ... } // real class
}
Daniel C. Sobral
fonte
18
Aparecendo anos depois para dizer: Acho que essa é uma boa resposta para a pergunta, mas uma solução ruim para o problema. Se algum futuro programador fosse ao código de Aleksander, ele diria "Ah, o construtor primário é privado, mas outros construtores não são." Se aquele programador visse o código de Daniel, ele diria: "Ah, eles estão usando um padrão de fábrica para compensar a incapacidade do Scala de marcar os construtores padrão como privados. Espere, o Scala pode marcar os construtores padrão como privados! O que está acontecendo aqui?!?" Em outras palavras, uma relação WTF / LOC ruim.
Malvolio
20
@Malvolio Não concordo muito. Este padrão não apenas torna privado o construtor primário, mas também a implementação , forçando o usuário a utilizar a interface (característica). Isso tem seu próprio valor. Quanto a alguém que pensa algo porque não conhece a língua - besteira! Para citar Kenny Tilton, aprenda a maldita língua !
Daniel C. Sobral
7
Deve ser mencionado em algum lugar que esta abordagem significa não usar a newpalavra - chave.
Travis Parks
1
Uma advertência com essa abordagem é que alguém ainda pode instanciar um Foo por meio de sua própria implementação. Isso pode ser visto como uma vantagem ou desvantagem dependendo do motivo do controle da construção.
aij
1
@aij Verdade, então fiz isso de forma que não pudesse mais acontecer. :)
Daniel C. Sobral