Privater und geschützter Konstrukteur in Scala

109

Ich war neugierig auf die Auswirkungen, wenn in Scala kein expliziter Primärkonstruktor vorhanden ist, sondern nur auf den Inhalt des Klassenkörpers.

Insbesondere vermute ich, dass das private oder geschützte Konstruktormuster, dh die Steuerung der Konstruktion über das Begleitobjekt oder die Methoden einer anderen Klasse oder eines anderen Objekts, möglicherweise keine offensichtliche Implementierung aufweist.

Liege ich falsch? Wenn ja, wie wird es gemacht?

Don Mackenzie
quelle
Sie könnten einen Scala-Singleton (dh mit dem Objektschlüsselwort) haben und Ihre Klasse innerhalb dieses Singletons als privat definieren und über Methoden des Singletons zum Erstellen Ihrer Objekte verfügen.
Paggas
@Paggas, leider wird eine Instanz einer Klasse, die als privat außerhalb ihres Gültigkeitsbereichs markiert ist, nicht kompiliert, selbst wenn sie von einer Methode zurückgegeben wird, die sich im Begleitobjekt des Gültigkeitsbereichs befindet.
Don Mackenzie
Dies geschieht im gesamten Scalaz-Quellcode sehr häufig. Das Konzept wird auch als abstrakter algebraischer Datentyp bezeichnet.
Tony Morris

Antworten:

190

Sie können den Standardkonstruktor als privat / geschützt deklarieren, indem Sie das entsprechende Schlüsselwort zwischen dem Klassennamen und der Parameterliste wie folgt einfügen:

class Foo private () { 
  /* class body goes here... */
}
Aleksander Kmetec
quelle
Danke Aleksander, können Sie mir bitte sagen, ob dies in einem der Scala-Bücher oder in der Sprachspezifikation dargestellt ist? Entschuldigung, ich kann noch nicht upvoten.
Don Mackenzie
Ich habe nur einen Blick auf die Erklärung der Konstruktoren von "Programming Scala" geworfen (Seiten 92-95) und sehe dort keine Erwähnung. Ich habe die Antwort auf Ihre Frage tatsächlich in einem alten Changelog gefunden, aber ich habe noch nie zuvor gesehen, dass sie irgendwo anders erwähnt wurde. Link: scala-lang.org/node/43#2.4.0
Aleksander Kmetec
18
Seite 414 von "Programmieren in Scala". Seite 97 von Wamplers Programmierskala. Seite 60 von Subramaniams Programmierskala. Ich habe momentan kein PDF von Beginning Scala bei mir, um es mir anzusehen.
Daniel C. Sobral
Oh, ich sehe es jetzt auf Seite 97. Danke.
Aleksander Kmetec
1
Vielen Dank für die weitere Recherche. Ich habe das Wampler-Buch, aber nur auf meinem Handy, und habe es offensichtlich nicht gründlich gelesen, aber ich habe festgestellt, dass es das Odersky-Buch überraschend gut ergänzt.
Don Mackenzie
64

Aleksanders Antwort ist richtig, aber die Programmierung in Scala bietet eine zusätzliche Alternative:

sealed trait Foo {
 // interface
}

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

  private class FooImpl(...) extends Foo { ... } // real class
}
Daniel C. Sobral
quelle
18
Kommen Sie Jahre später vorbei, um zu sagen: Ich denke, dies ist eine gute Antwort auf die Frage, aber eine schlechte Lösung für das Problem. Wenn ein zukünftiger Programmierer Aleksanders Code verwenden würde, würde er sagen: "Ah, der primäre Konstruktor ist privat, andere Konstruktoren jedoch nicht." Wenn dieser Programmierer Daniels Code betrachten würde, würde er sagen: "Ah, sie verwenden ein Factory-Muster, um die Unfähigkeit von Scala zu kompensieren, die Standardkonstruktoren als privat zu markieren. Warten Sie, Scala kann die Standardkonstruktoren als privat markieren! Was ist los?" hier?!? " Mit anderen Worten, ein schlechtes WTF / LOC-Verhältnis.
Malvolio
20
@ Malvolio Ich stimme nicht ganz zu. Dieses Muster macht nicht nur den primären Konstruktor privat, sondern auch die Implementierung , wodurch der Benutzer gezwungen wird, die Schnittstelle (Merkmal) zu verwenden. Das hat seinen eigenen Wert. Was jemanden betrifft, der etwas denkt, weil er / sie die Sprache nicht kennt - piffle! Um Kenny Tilton zu zitieren, lerne die verdammte Sprache !
Daniel C. Sobral
7
Es sollte irgendwo erwähnt werden, dass dieser Ansatz bedeutet, das newSchlüsselwort nicht zu verwenden .
Travis Parks
1
Eine Einschränkung bei diesem Ansatz ist, dass jemand einen Foo durch seine eigene Implementierung instanziieren kann. Dies kann je nach Grund für die Steuerung der Konstruktion als Vor- oder Nachteil angesehen werden.
aij
1
@aij Stimmt, also habe ich es so gemacht, dass das nicht mehr passieren kann. :)
Daniel C. Sobral