7
votes

Comment instantiier des classes immuables dans une association bidirectionnelle?

J'ai deux classes immuables: Utilisateur strong> et Ministère Strong>, ils sont connectés à l'aide d'une association bidirectionnelle - Strong> a une référence à Département strong> et département strong> a une liste d'un utilisateur fort> s. Comment créer un nouveau ministère Strong> instance avec les utilisateurs fournis forts>?

code: p>

class User {
    private final Department department;
    private final String name;

    public User(Department department, String name) {
        this.department = department;
        this.name = name;
    }
}

class Department {
    private final List<User> users;
    private final String name;

    public Department(List<User> users, String name) {
        this.users = new ArrayList<>(users);
        this.name = name;
    }
}


8 commentaires

Si vous voulez vraiment immuable département Vous devez utiliser quelque chose comme users = collections.unmodifiablelist (utilisateurs) . Mais vous aurez perdu la capacité d'ajouter des utilisateurs après cela et votre tâche devient impossible :)


@Andremoniy qui ne fera pas la classe immuable, puisque l'appelant a toujours une référence à la liste mutable enveloppée dans une liste non modifiable.


Vous posez des questions sur les principes de conception. Mais considérez ceci: si la classe de département devrait-elle vraiment être immuable? N'est-il pas mieux adapté comme une classe mutable qui pourrait ajouter et / ou supprimer des utilisateurs? Une fois cette question répond à oui, pensez à la meilleure façon de mettre en œuvre cela. Le constructeur devrait-il vraiment prendre une liste? Ou la classe elle-même devrait-elle fournir un ajouter et un supprimer la méthode . Au moment où vous avez conçu un département comme ayant une liste contenant des utilisateurs. Mais vous devez concevoir un département comme ayant des utilisateurs. C'est une différence!


@Jbnizet vraiment? Et comment l'appelant peut archiver cette référence?


@Andreemoniy Il s'agit d'une question de conception fondamentale. En fait, il est faux de disposer d'un constructeur d'accepter un argument de liste!


Liste mutable = nouvelle arrayliste <> (); Département D = nouveau département (mutable); mutable.add (nouvel utilisateur ());


@Jbnizet ARH, tu veux dire ça. D'accord


Ooops! J'avais tort avec mon premier commentaire. OP est la copie du contenu, pas simplement la copie de la référence! Honte sur moi ...


6 Réponses :


1
votes

Département instancier avec la liste vide des utilisateurs. Ensuite, utilisez le service pour instantiier l'utilisateur et ajouter l'instance utilisateur à la liste des utilisateurs du département.


1 commentaires

Dans ce cas, département S est toujours mutable :-(



5
votes

Je ressens en vous cas de cas, vous pouvez modifier légèrement votre conception et utiliser spécial usersBuilder , c'est-à-dire xxx

en général, ce n'est pas vraiment une bonne idée d'utiliser des objets référence avant que son constructeur se termine; Mais dans ce cas particulier, il semble sûr.

dans ce cas ces objets seront vraiment immuables.


0 commentaires

1
votes

Une approche est de modifier légèrement ce que vous comprenez immuable à signifier. Dans la conception orientée objet, il est conventionnel de distinguer entre les les attributs d'un objet et de ses associations . Les objets associés sont des entités différentes auxquelles l'objet a des références. Si vous détendez la définition de immuable pour signifier que les attributs de l'objet ne changent pas, mais permettent aux associations de changer, vous évitez ce type de problème.

Dans votre cas, utilisateur et département des objets serait associé les uns aux autres, et chacun aurait un attribut nom


0 commentaires

1
votes

Vous pouvez produire des services immuables et des utilisateurs avec un constructeur supplémentaire sur le département. Du code des questions, il est déduit que

  • Un objet utilisateur n'est qu'une association entre une chaîne et un département li>
  • Les références utilisateur ne peuvent pas exister sans référence de département. Li> ul>

    Étant donné que les utilisateurs ne sont vraiment que des chaînes associées à un département, un département peut être construit avec une liste code> qui représente tous les noms d'utilisateur à inclure et à utiliser ce Liste code> Pour créer une liste code> dans le constructeur de département. p>

    Note: Que @andreemoniy a déclaré à propos de laisser ceci code> échappe à un Le constructeur ne doit pas être utilisé, mais il est en sécurité dans ce cas, car il ne s'agit que d'un constructeur d'instance utilisateur où cette instance utilisateur n'est pas accessible avant que le constructeur de département ne revienne. p>

    Voici à quoi cela ressemblerait, dans Java 8: P>

    public final class User {
        private final Department department;
        private final String name;
    
        public User(Department department, String name) {
            this.department = department;
            this.name = name;
        }
    
        public Department getDepartment() {
            return department;
        }
    
        public String getName() {
            return name;
        }
    }
    
    public final class Department {
        private final List<User> users;
        private final String name;
    
        ///Reversed argument list to avoid collision after erasure
        public Department(String name, List<String> users) {
            this.users = Collections.unmodifiableList(users.stream()
                    .map((s) -> new User(this,s)).collect(Collectors.toList()));
            this.name = name;
        }
    
        public Department(List<User> users, String name) {
            this.users = Collections.unmodifiableList(users);
            this.name = name;
        }
    
        public List<User> getUsers() {
            return users;
        }
    
        public String getName() {
            return name;
        }
    }
    


0 commentaires

1
votes

Je pense que c'est une question de modélisation également. Ceci est correct de penser qu'un utilisateur a un département et un département ont des utilisateurs, mais la question est de la profondeur que vous pouvez regarder dans les données de l'utilisateur et du département?

Cela a-t-il un sens à moins que vous accédez conceptuellement d'accéder à User.Department.user [2] .name? Qu'en est-il du département.User [10] .Addresses [1] .street?

Je ne pense vraiment pas sur la plupart des scénarios. C'est une question de domaine d'information. Vous avez des bondaires tout en accédant à des données et que cela peut également être exprimé d'une manière d'une manière ou d'une autre dans vos modèles.

Si la modélisation de l'objet genre représente le monde réel, c'est bon de penser que lorsque vous allez dans un département, vous verrez des dizaines Des personnes travaillant là-bas et tout de probabilité que tout ce que vous pourrez savoir à leur sujet est le comptage et les noms peut-être. Donc, quelles tranches de données vous devriez pouvoir voir de votre objet?

Mon approche pour cela est: xxx

Je ne pense pas que je ne pense pas D Besoin de montrer comment les constructeurs fonctionnent depuis si vous avez remarqué que ce scénario, la nature bidirectionnelle de la relation n'est jamais là. Ainsi, lorsque vous construisez une personne, tout ce dont vous avez besoin est le MinistèreInfo (département Aucun employé non requis) et la même chose est valable lorsque vous construisez un département, lorsque tout ce que vous avez besoin d'avoir est le personnage des employés du département. < P> C'est ma façon de penser que ce problème conceptuellement. Des commentaires?


2 commentaires

Merci pour la réponse, j'ai une réponse ajoutée avec une autre solution, semblable à votre idée, qu'en pensez-vous de cela?


C'est à peu près beaucoup, sinon je ne pense pas que ce soit une vraie bonne chose d'avoir une sorte d'entité appelée des département des ministères, mais cela fonctionne sûrement bien. Mon moyen de s'attaquer à ce que c'est la même chose, mais je préférais attraper les informations de base dans une * entité info



0
votes

Ma solution consiste à: diviser l'une des classes immuables en deux classes: une classe avec les attributs et une classe avec l'association bidirectionnelle: xxx

afin de créer un nouvel utilisateur et un instance de service que vous devez:

  • Créer une nouvelle instance de départ
  • Créez une nouvelle instance utilisateur et passez l'instance de service créée
  • créer une nouvelle instance de département et passez l'instance utilisateur créée

0 commentaires