9
votes

Éliminer plusieurs héritage

J'ai le problème suivant et je me demande s'il y a une bonne façon de modéliser ces objets sans utiliser de héritage multiple. Si cela fait une différence, j'utilise Python.

Les étudiants ont besoin d'informations de contact plus des informations sur les étudiants. Les adultes ont besoin d'informations de contact plus les informations de facturation. Les étudiants peuvent être des étudiants adultes, auquel cas j'ai besoin de contacts / d'informations d'étudiant / de facturation, ou ils peuvent être des enfants, auquel cas j'ai besoin d'informations de contact / étudiant / parent.

Juste pour être clair sur la manière dont le système sera utilisé, je dois être capable de demander une liste de tous les adultes (et je vais recevoir des étudiants adultes plus les parents) ou une liste de tous les étudiants (et je vais obtenir Étudiants enfants plus étudiants adultes).

En outre, tous ces objets doivent avoir une classe de base commune.


4 commentaires

Cela ressemble vraiment à une tâche des devoirs. :)


@Brian MacKay: Probablement, mais je doute que c'est une mission directe des devoirs - c'est-à-dire «éliminer de multiples héritages» - mais fait probablement partie d'un projet de devoirs qu'il tente de trouver une manière différente de s'approcher. Il est certainement mieux demandé que certaines des questions de dépistage de copie / pâte que j'ai vues ici.


Je sais que ça fait, mais je peux vous assurer que ce n'est pas :)


C'est exactement le genre de problème que je travaille cette semaine! Les détails sont très différents, bien sûr. Certes, ce n'est pas des devoirs. Ma candidature est le numéro de science crunching.


8 Réponses :


2
votes

solution très simple: utilisez la composition plutôt que l'héritage. Plutôt que d'avoir des étudiants hériter de contact et de facturation, apportez un champ / un attribut de personne et d'hériter de cela. Faire de la facturation un champ d'étudiant. Faire parent un champ de référence auto-référentiel.


0 commentaires

2
votes

Cela ne sonne pas comme si vous avez vraiment besoin de multiples héritage. En fait, vous n'avez jamais vraiment besoin héritage multiple. C'est juste une question de savoir si plusieurs héritages simplifient les choses (que je ne pouvais pas voir comme étant le cas ici).

Je créerais une classe de personne qui a tout le code que l'adulte et l'étudiant partageraient. Ensuite, vous pouvez avoir une classe d'adulte qui possède toutes les choses qui seulement les besoins des adultes et une classe enfant qui possède le code seul les besoins de l'enfant.


1 commentaires

La classe de la personne serait énorme. Chaque fois qu'un nouveau type de contact a été ajouté, une personne augmenterait et une ou plusieurs autres classes d'enveloppe augmenteraient également. Alex Martelli a raison.



8
votes

Ce que vous avez est un exemple de rôle - c'est un piège commun pour modéliser le rôle par héritage, mais les rôles peuvent changer et changer la structure d'héritage d'un objet (même dans les langues où il est possible, comme Python) n'est pas recommandé. Les enfants grandissent et deviennent des adultes et certains adultes seront également des parents d'étudiants pour enfants ainsi que des étudiants adultes eux-mêmes - ils pourraient alors déposer à l'un ou l'autre des enfants, mais il est nécessaire de garder l'autre (leur enfant change d'écoles, mais ils ne le font pas, ni des vexives) .

Il suffit d'avoir une personne de classe avec des champs obligatoires et des options facultatives, et celle-ci, représentant des rôles, peut changer. "Demander une liste" (assez indépendamment de l'héritage ou autrement) peut être fait soit en construisant la liste à la volée (parcourir tous les objets pour vérifier que chacun soit satisfait aux exigences) ou en maintenant les listes correspondant aux exigences possibles (ou à un mélange des deux stratégies pour des requêtes fréquentes et ad hoc). Une base de données de quelque sorte est susceptible d'aider ici (et la plupart des DBS fonctionnent bien mieux sans héritage dans la voie; -).


2 commentaires

Est la raison pour laquelle vous recommandez cette solution parce que les rôles peuvent changer?


Oui, la mutabilité du rôle [S] est la motivation n ° 1 pour éviter l'héritage dans ce cas (il y en a d'autres aussi, qui s'appliquent plus largement et que d'autres réponses ont été mentionnées).



5
votes

Alors que je suis sûr que quelqu'un d'autre commentera bientôt (s'ils ne l'ont pas déjà), un bon principe oo est " La composition favorise sur l'héritage ". De votre description, il semble suspendre de façon suspicieusement que vous brisez le Principe de responsabilité unique et devrait être décomposer la fonctionnalité en objets distincts.

Il me semble également que Python prend également en charge dactylographie de canard , qui supplie la question "Pourquoi Est-il si important que toutes les classes aient une classe de base commune? "


2 commentaires

+1 pour relier la composition de faveur sur l'héritage. Exactement mon point!


N'oubliez pas que, comme indiqué dans l'article lié, la composition est la plus fréquemment mise en œuvre via l'interface héritage. Si tel est le cas, il reste encore le problème initial.



0
votes

Une solution consiste à créer une classe / interface d'informations de base que les classes contactInfo, StudentInfo et BillingInfo hériter de. Demandez à une sorte d'objet personne qui contient une liste d'objets d'information, puis vous pouvez remplir la liste des objets d'information avec contactInfo, StudentInfo, etc.


0 commentaires

1
votes

Cela ressemble à quelque chose qui pourrait être fait assez bien et de manière flexible avec une architecture de composants, comme Zope.comPonents. Les composants sont d'une sorte d'une sorte de motifs de composition super flexibles.

Dans ce cas, je finirais probablement de faire quelque chose lorsque vous chargez les données pour définir également les interfaces de marqueur en fonction de certaines informations, telles que l'âge> = = 18 Vous définissez l'interface IADULT, etc. Vous pouvez ensuite obtenir les informations adultes en effectuant xxx

ou quelque chose comme ça. (EDIT: effectivement j'utiliserais probablement xxx

pour obtenir tous les schemas en une fois. :)

une architecture de composant mai Soyez surchargé, mais une fois que vous êtes habitué à penser comme ça, de nombreux problèmes deviennent triviaux. :)

Découvrez les courriels Excellent PyCon Talk à ce sujet: http: // www.youtube.com/watch?v=uf77e2teeqo Et mon poteau de blog intro: http: //regebro.wordpress .COM / 2007/11/16 / A-Python-composant-architecture /


0 commentaires

1
votes

Je pense que vos besoins sont trop simplifiés, car dans une situation réelle, vous pourriez avoir des étudiants ayant leurs propres comptes pour gérer la facturation même si elles sont des mineurs qui ont besoin d'informations de contact des parents. De plus, vous pourriez avoir des informations de contact parental diffèrent des informations de facturation dans une situation réelle. Vous pourriez également avoir des étudiants adultes avec quelqu'un d'autre à la facture. Mais, de côté - en regardant vos exigences, voici une façon:

cours: personne, billinginfo, étudiantinfo. P>

Toutes les personnes sont des instances de la personne de classe ... p>

class Person:
    # Will have contact fields all people have - or you could split these off into an
    # object.
    parent        # Will be set to None for adults or else point to their parent's
                  # Person object.
    billing_info  # Set to None for non-adults, else to their BillingInfo object.
    student_info  # Set to None for non-student parents, else to their StudentInfo
                  # object. 


0 commentaires

0
votes

en pseudocode, vous pouvez faire quelque chose comme ceci: xxx pré>

alors vous pouvez créer une classe appelée étudiantmanager: p>

Public Class StudentManager
    Public Function GetAdults(studentCollection(Of Students)) as StudentCollection(Of Students)
        Dim ResultCollection(Of Students)

        ...Loop through studentCollection, adding all students where Student.StudentType=Adult  

        Return ResultCollection
    End Function


    [Other Functions]
End Class

Public Enum StudentType
    Adult=0
    Child=1  
End Enum


0 commentaires