Constructeur privé et protégé à Scala

109

J'ai été curieux de savoir l'impact de ne pas avoir de constructeur primaire explicite dans Scala, juste le contenu du corps de la classe.

En particulier, je soupçonne que le modèle de constructeur privé ou protégé, c'est-à-dire le contrôle de la construction via l'objet compagnon ou les méthodes d'une autre classe ou d'un objet, pourrait ne pas avoir une implémentation évidente.

Ai-je tort? Si oui, comment est-il fait?

Don Mackenzie
la source
Vous pouvez avoir un singleton Scala (avec le mot-clé object, c'est-à-dire), définir votre classe comme privée dans ce singleton et avoir des méthodes du singleton pour construire vos objets.
Paggas
@Paggas, malheureusement, lorsque vous retournez une instance d'une classe marquée comme privée hors de sa portée, elle ne se compilera pas, même lorsqu'elle est renvoyée par une méthode de l'objet compagnon de portée.
Don Mackenzie
Cela se fait assez abondamment dans tout le code source de Scalaz. Le concept est également connu sous le nom de type de données algébrique abstrait .
Tony Morris

Réponses:

190

Vous pouvez déclarer le constructeur par défaut comme privé / protégé en insérant le mot clé approprié entre le nom de la classe et la liste de paramètres, comme ceci:

class Foo private () { 
  /* class body goes here... */
}
Aleksander Kmetec
la source
Merci Aleksander, pouvez-vous me dire si cela est présenté dans l'un des livres scala ou dans la spécification de la langue? Désolé, je ne peux pas encore voter.
Don Mackenzie
Je viens de jeter un coup d'œil sur l'explication des constructeurs par "Programming Scala" (pages 92-95) et je ne vois pas cela mentionné ici. En fait, j'ai trouvé la réponse à votre question dans un ancien journal des modifications, mais je ne l'ai jamais vue mentionnée ailleurs auparavant. Lien: scala-lang.org/node/43#2.4.0
Aleksander Kmetec
18
Pag 414 de "Programmation en Scala". Page 97 de la programmation Scala de Wampler. Page 60 de la programmation Scala de Subramaniam. Je n'ai pas de PDF de Beginning Scala avec moi pour le moment.
Daniel C. Sobral
Oh, je le vois maintenant à la page 97. Merci.
Aleksander Kmetec
1
Merci à la fois pour les recherches plus poussées, j'ai le livre Wampler, mais uniquement sur mon téléphone et je ne l'ai clairement pas lu à fond, mais j'ai trouvé qu'il complète étonnamment bien le livre Odersky.
Don Mackenzie
64

La réponse d' Aleksander est correcte, mais la programmation dans Scala offre une alternative supplémentaire:

sealed trait Foo {
 // interface
}

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

  private class FooImpl(...) extends Foo { ... } // real class
}
Daniel C. Sobral
la source
18
Popping quelques années plus tard pour dire: je pense que c'est une bonne réponse à la question mais une mauvaise solution au problème. Si un futur programmeur utilisait le code d'Aleksander, il dirait "Ah, le constructeur principal est privé mais les autres constructeurs ne le sont pas." Si ce programmeur regardait le code de Daniel, il dirait: "Ah, ils utilisent un modèle Factory pour compenser l'incapacité de Scala à marquer les constructeurs par défaut comme privés. Attendez, Scala peut marquer les constructeurs par défaut comme privés! ici?!?" En d'autres termes, un mauvais rapport WTF / LOC.
Malvolio
20
@Malvolio Je ne suis pas tout à fait d'accord. Ce modèle rend non seulement le constructeur principal privé, mais aussi l' implémentation , forçant l'utilisateur à utiliser l'interface (trait). Cela a sa propre valeur. Quant à quelqu'un qui pense à quelque chose parce qu'il ne connaît pas la langue - piffle! Pour citer Kenny Tilton, apprenez la putain de langue !
Daniel C.Sobral
7
Il convient de mentionner quelque part que cette approche signifie ne pas utiliser le newmot - clé.
Travis Parks
1
Une mise en garde avec cette approche est que quelqu'un peut toujours instancier un Foo via sa propre implémentation. Cela pourrait être considéré comme un avantage ou un inconvénient selon la raison du contrôle de la construction.
aij
1
@aij True, donc je l'ai juste fait pour que cela ne puisse plus arriver. :)
Daniel C. Sobral