J'ai donc décidé d'utiliser le modèle de conception d'usine avec une injection de dépendance.
class ClassA { Object *a, *b, *c; public: ClassA(Object *a, Object *b, Object *c) : a(a), b(b), c(c) {} }; class ClassB : public ClassA { Object *d, *e, *f; public: ClassB(Object *a, Object *b, Object *c, Object *d, Object *e, Object *f) : ClassA(a, b, c), d(d), e(e), f(f) {} };
3 Réponses :
Ceci est l'un des problèmes C ++ (si cela peut être appelé un problème). Il n'a pas de solution autre que d'essayer de conserver le nombre de paramètres de la CTOR minimale.
Une des approches utilise les accessoires STRIT comme: P>
struct PropsA { Object *a, *b, *c; }; class ClassA { ClassA(PropsA &props, ... other params); };
Dans la plupart des cas, il serait logique de faire propsa code> une classe à part entière en appuyant également des méthodes associées. Sinon, vous venez de vous retrouver avec une structure de données qui n'est pas très orientée objet.
J'ai mis les exigences de l'application, de la rapidité du développement et de la clarté du code de loin devant les affaires fantaisistes d'être "orienté objet".
OOP n'est pas "fantaisie", mais c'est un choix que vous prenez ou laissez. Je vais bien avec quelqu'un qui le fait juste de la manière procédurale, en utilisant des structures et des fonctions, mais si vous envisagez d'utiliser des classes, il est payant de mettre des efforts pour le faire correctement, sinon vous vous retrouvez dans un désordre où la moitié de votre code est orienté objet et le reste est procédural - je ne pense pas que cela conduit beaucoup de clarté.
Le OOP lui-même n'est pas fantaisiste. C'est un ensemble de méthodes extrêmement utiles. Seulement il est nécessaire de penser à quels éléments de cet ensemble sont utiles dans chaque cas, et seulement après avoir pensé à les utiliser. Si quelque chose n'a pas de méthodes raisonnables et / ou de vivre pendant une courte période - il devrait être une structure. Et il est juste que ce soit une structure. Cela ne rend pas le code moins orienté objet. OOP juste pour OOP - c'est des trucs de fantaisie inutiles.
Je suis totalement d'accord que les structures ont leur place, mais c'est pourquoi j'ai dit "dans la plupart des cas, ..." - Dans la plupart des cas, lorsqu'un constructeur prend des arguments "trop nombreux", c'est un signe que la classe fait trop et pourrait être refoulé dans des classes plus petites.
Cela peut être que j'étais trop dur. Désolé. "Dans la plupart des cas" me semblait "toujours avec de rares exceptions près". "C'est un signe que la classe fait trop" - oui, cela peut être un signe. Seulement avant de refactoriser qu'il reste nécessaire de procéder à une évaluation si ce morceau de code est le pire de l'ensemble du projet ou non. Très probablement que autre lieu a besoin d'une attention plus urgente.
Pas de soucis. En effet, je suis un peu puriste OO, et lorsque quelqu'un marge une question avec "oop" ou "motifs de conception", je suis naturellement enclin à discuter de la bonne voie plutôt que la solution la plus rapide. :)
Cette méthode ressemble à "modèle d'objet de paramètre" et bonne option. Discussion similaire: Stackoverflow.com/questions/5551640/...
Setter ne sont pas recommandés pour de telles choses car elles produisent un objet partiellement construit qui est sujette très erronée. Un modèle commun pour la construction d'un objet nécessitant de nombreux paramètres est l'utilisation du constructeur. La responsabilité de Classbbuilder est de créer des objets de classe. Vous faites du Constructeur Classb Private et permet à seulement un constructeur de l'appeler à l'aide de la relation d'amis. Maintenant, le constructeur peut sembler d'une manière ou d'une autre comme ça et que vous utilisez le constructeur aime ceci: p> ClassB* b = ClassBBuilder().setName('alice').setSurname('Smith').build();
Cela peut être un peu plus agréable que les configurateurs, mais vous retardez efficacement la vérification de suffisamment d'informations sont présentes pour construire un objet à l'exécution du temps. Je ne considère pas qu'une amélioration sur un constructeur uni prenant quelques arguments.
Si vous souhaitez une mise en œuvre du temps compilé, vous pouvez toujours bénéficier du constructeur. C'est le cas lorsqu'un constructeur de classe prend de nombreux paramètres facultatifs avec des valeurs par défaut. Ensuite, vous pouvez utiliser les setters de Builder pour définir ces paramètres facultatifs et avoir la méthode de construction () prendre tous les paramètres requis. Cela vous donnerait la compilation de l'exécution du temps que tous les paramètres requis sont dépassés, mais seront plus lisibles et moins enclins à un appel à un constructeur qui prend de nombreux paramètres certains d'entre eux ont besoin d'une partie d'entre elles en option avec des valeurs par défaut.
J'aime cette approche. Le code pour un client construit l'objet est beaucoup plus propre. Bien que c'est vrai que vous perdiez la vérification de l'heure de la compilation, la fonction Build () permet toujours de vérifier votre code de validation dans votre code.
Je pense que ce que vous décrivez n'est pas un problème dans C ++ - en fait, C ++ reflète les dépendances exprimées de votre conception assez bien: P>
classa code>, vous devez avoir trois instances code> objet code> ( A code>, b code> et c code>). li>
- Pour construire un objet de type
Classb code>, vous devez également avoir trois instances code> objet code> ( d code>, E code > et f code>). li>
- Chaque objet de type
classb code> peut être traité comme un objet de type classa code>. li>
ol>
Cela signifie que pour la construction d'un objet de type Classb code>, vous devez fournir trois objets code> objet code> nécessaires à la mise en oeuvre du classa code> interface, puis trois autres pour la mise en oeuvre de l'interface classb code>. p>
Je crois que le problème réel em> est votre conception. Vous pouvez envisager différentes approches pour résoudre ce problème: p>
- Ne laissez pas
classb code> hériter classa code>. Peut être une option selon que vous avez besoin d'un accès homogène aux objets de l'un ou l'autre type (par exemple, car vous avez une collection de classa * code> et cette collection pourrait également contenir des pointeurs sur Classb < / code>). li>
- Recherchez des objets qui apparaissent toujours ensemble. Comme - peut-être les deux premiers objets passés à l'un ou l'autre constructeur (
a code> et b code> ou d code> et E code>) représentent certains sorte de paire. Peut-être qu'un identifiant d'objet ou similaire? Dans ce cas, il peut être utile d'introduire un résumé dédié (lecture: type) pour cela. Li>
ol>
Mon approche générale consiste à éviter le nombre de héritiers autant que possible et à essayer de garder chaque classe axée sur une responsabilité unique. Pourriez-vous construire
classa code> séparément, puis initialiser
classb code> avec une référence à cela, plutôt que de les coupler étroitement par héritage?
Mike Seymour a raison. Préfère une relation A-A-A (composition) au plus étroitement couplé est-une relation (héritage). Peut-être que si vous expliquez ce que vous voulez faire, nous pouvons vous dire à quel point il est préférable de l'accomplir?
Je ne vois aucun problème majeur avec héritage. Il devrait être utilisé partout où il est nécessaire. Il ne devrait pas être abusé comme tout le reste.
@Kirillkobelev: Je suis tout à fait d'accord; Il devrait être évité à moins d'être nécessaire.
Qu'est-ce qui constitue «trop d'arguments»? Lors de l'utilisation du CIO, le conteneur prend soin d'eux et cela ne se produit que lorsque vous Héritage d'abus B> ou avez un «objet de Dieu» qui fait tout et dépend de l'univers.