2010-10-22 2 views
3

Par exemple (peut-être un peu maladroit d'une véritable vision de la vie, mais juste pour illustrer):Puis-je définir une classe sans constructeur public et placer une méthode factory pour les objets de cette classe dans une classe différente dans Scala?

« Utilisateur » est un cas classe contenant le nom d'utilisateur et id. L'ID ne peut jamais être défini manuellement et une instance de classe User sans ID n'a aucun sens.

Une classe UserBase gère la base des utilisateurs et possède une méthode "getUser (name: String): User" renvoyant une instance utilisateur cohérente. Personne d'autre qu'un objet UserBase ne peut savoir (bien que quelqu'un puisse, mais ne devrait pas s'appuyer sur cette connaissance) l'identifiant d'un utilisateur, donc construire une instance User n'a aucun sens (et peut causer des erreurs dans le futur si quelqu'un accidentellement le code et oublie). De plus, avoir une instance d'utilisateur orpheline qui n'est pas suivie par une UserBase n'est pas non plus souhaitable. Par conséquent, la tâche consiste à appeler uniquement UserBase.getUser pour obtenir une instance User.

Est-ce que cela peut être implémenté dans Scala?

+0

Cette question est ancienne maintenant, vous devriez probablement accepter l'une des réponses. Ou modifiez-le pour fournir plus d'informations si vous n'obtenez pas le type de réponse que vous espériez. –

Répondre

2

Vous devez placer les classes dans le même package ou les intégrer à la même classe ou à un même objet. Puis:

object O { 
    class C private[O] (val x: Int) { } 
    object D { def apply(i:Int) = new C(i) } 
    def getC(i:Int) = new C(i) 
} 

scala> O.D(5) 
res0: O.C = [email protected] 

scala> new O.C(5) 
<console>:10: error: constructor C cannot be accessed in object $iw 
     new O.C(5) 

scala> O.getC(5) 
res1: O.C = [email protected] 
1

Une classe de cas obtient automatiquement plusieurs fonctionnalités, y compris un objet compagnon avec une méthode apply() pour construire des instances de la classe. C'est pourquoi vous n'avez pas besoin de "nouveau" avec des classes de cas. Si vous essayez de faire un compagnon explicite avec apply(), vous obtiendrez error: method apply is defined twice

Si vous souhaitez créer votre propre méthode d'usine, vous ne devez pas utiliser de classes de cas. Vous pouvez toujours avoir les mêmes caractéristiques (toString, apply, unapply, etc) mais vous devrez les implémenter manuellement et selon vos propres spécifications.

+0

Merci, une information utile à connaître. Mais cela ne répond pas à la question, qui est de ne faire ni un constructeur ni «appliquer» disponible ailleurs que dans une classe particulière (différente). En C++, j'utiliserais probablement la définition "friend" (pour autant que je me souvienne, mon expérience en C++ était il y a plusieurs années) pour rendre un membre privé disponible pour une autre classe, mais je n'ai aucune idée sur comment l'atteindre en Scala. – Ivan

+0

Dans scala vous pouvez définir le niveau de hiérarchie pour 'private' comme' private [what] 'où' what' peut être un niveau englobant de paquet ou de hiérarchie d'objets ou 'this'. Quelqu'un a répondu ci-dessous avec un exemple. –

1

Vous ne clarifient pas vraiment ce qu'est une « base » est dans ce contexte, mais étant donné votre description, il semble que cela est vraiment rien de plus qu'une usine pour les utilisateurs.

Le lieu habituel de mettre une usine pour une classe est dans l'objet compagnon (Voici comment les classes de cas font, mais la technique ne se limite pas à seulement classes de cas)

class User private(val id: Int, val name: String) { 
    ... 
} 

object User { 
    private def nextId() : Int = ... 
    def apply(name: String) = new User(nextId(), name) 
} 

//now create one: 
val u = User("Ivan") 

de Bien sûr, si l'objet User est immuable (hautement recommandé), il y a très peu de raisons de cacher le membre id. Vous allez probablement aussi vouloir une méthode (restreinte) pour construire un User avec un ID spécifié, principalement pour des raisons de tests unitaires.

En travaillant avec des compagnons comme celui-ci, il est également peu probable que vous ayez toujours besoin d'une usine distincte UserBase. Si votre usine porte le même nom que les instances qu'elle génère, le code sera plus clair.

+0

Head's up, lors de l'enregistrement ci-dessus dans un fichier, et en essayant ': charger le fichier' d'un REPL, vous pouvez rencontrer ce problème: http://forums.pragprog.com/forums/87/topics/4153 – opyate

Questions connexes