J'ai récemment vu une question de conception OO sur un forum et j'ai commencé à penser à l'utilisation de RTTI. Cependant, cela doit être un mauvais design mais je suis incapable de penser à une alternative. Voici la simple question: p>
Créer un programme C ++ pour le scénario suivant à l'aide des concepts OO - P>
Mon chien, Named Buddy, vit dans la cour. Il aboie la nuit quand il voit un chat ou un écureuil qui est venu à visiter. S'il voit une grenouille et qu'il a faim, il le mange. S'il voit une grenouille et il n'a pas faim, il joue avec elle. S'il a déjà mangé 2 grenouilles, et a toujours faim, il le laissera partir. S'il voit un coyote, il crie de l'aide. Parfois, son ami tape s'arrête, et ils se chassent. S'il voit un autre animal, il le regarde tout simplement. Je m'attendrais à ce que vous ayez une classe d'animaux et un chat, un chien, un écureuil, une classe Coyote qui hérite de la classe d'animaux. P> blockQuote>
J'ai commencé à penser à avoir une méthode See () dans la classe de chiens qui prend un argument d'animal puis vérifie le type réel de l'objet (grenouille, chat, etc.) et prend l'action requise - la lecture, la chasse, etc. en fonction du Type réel. Cependant, cela nécessiterait RTTI qui doit être une mauvaise conception. Quelqu'un peut-il suggérer une meilleure conception qui éviterait RTTI et signaler également l'erreur de ma pensée? p>
4 Réponses :
indice: utilisez des fonctions virtuelles (sur les animaux cibles) au lieu de RTTI. P>
Et le mécanisme de fonction virtuelle n'utilise pas RTTI? o.o
En fait, comment feriez-vous cela? Les animaux ne devraient pas savoir quoi faire quand ils sont vus par un chien devraient-ils? Je pense que le chien aurait besoin d'identifier l'animal et de faire ce qu'il voulait en fonction de ce qu'il a perçu l'animal comme (un commutateur code> en termes de code). Je vais réellement aller avec RTTI dans ce cas.
@Azza Nope, il utilise une expédition dynamique, pas RTTI
Si ce problème est entièrement concentré sur le chien nommé Buddy, les classes d'animaux n'ont pas d'autre but, sauf pour informer Buddy Que faire à leur sujet, et le problème est probablement mieux formulé comme une fonction virtuelle sur la classe d'animaux. S'il y a plusieurs chiens "percevants", le problème devient alors l'une des doubles envisages, que peut i> avoir d'autres implémentations, mais en C ++ est probablement le mieux adapté par un voir () virtuel qui appelle un surcharge surchargé ( ) virtuel. (Le premier type peut toujours effectuer tout le travail nécessaire, si on y revient () les appelle.)
@Johncalsbeek cela a un peu de sens pour un animal de savoir quoi faire quand on le voit par un autre animal i>, par exemple, quand un ours voit un poisson (que je sache ou non) le Le poisson n'est pas codé avec "GET ATEND", c'est l'ours qui est codé avec "manger"
Une alternative qui permet aux sous-classes des animaux d'être indépendantes de Buddy est le modèle de visiteur.
@Sethcarnegie En effet, cela n'a pas de sens si vous considérez que les sous-classes des animaux sont des représentations (simulations, même) d'objets du monde réel. Cependant, vous pouvez aussi bien penser à eux comme des représentations de la perception de ces animaux I>, qui nécessite tout ce problème. Peut aussi bien résoudre le problème que le problème et obtenir une implémentation facile à comprendre dans le processus.
@Johncalsbeek alors il serait logique d'avoir une classe de base buddyperception code> à partir de laquelle ils dérivraient tous, puis ont la fonction accepter un
buddyperception et code> au lieu d'un animal
/ code>, non?
@Sethcarnegie certainement. Mais dans un programme qui a l'intention de simuler le comportement d'un agent, pratiquement tous les objets du programme seront une "perception" de quelque sorte. Vous vous retrouveriez avec animalerie code>,
FoodProception code>,
EmotionPECEception code>, etc. Si vous définissez votre domaine soigneusement, vous pouvez garder les noms simples et immobiles précis. Cependant, les défis de dénomination sont probablement hors de la portée de cette question.
@Johncalsbeek: de grands commentaires.
@SethCarnegie Je pensais que les informations RTTI ont été stockées dans VTable code> pour les classes polymorphes. Non?
Je suis vraiment confus. Quelqu'un pourrait-il clarifier ce concept de «perception» par exemple?
@ vjain27 Il s'agit vraiment de ce qu'il faut nommer vos cours. Dans la vraie vie, l'écureuil lui-même n'a aucun contrôle sur ce que Buddy fait quand il voit l'écureuil. Par analogie, la classe Squirrel code> ne doit plus jamais avoir à se référer à la classe code> Buddy code>. Sauf si i> le i> la classe d'écureuil code> représente les pensées de Buddy sur un écureuil, pas les comportements de l'écureuil lui-même.
@Johncalsbeek: Je ne reçois pas la différence entre les deux cas que vous avez mentionnés dans votre commentaire - 1. Avoir une fonction virtuelle en classe animale et 2. Avoir deux fonctions virtuelles - voir et voir. Je peux comprendre le second de l'exemple que vous avez déjà fourni. Pourriez-vous s'il vous plaît expliquer le premier?
@ vjain27 Dans l'exemple que j'ai fourni, vous remarquerez qu'aucun des méthodes code> code> est virtuelle. Si vous les faites virtuelle, ajoutez-les à Animal Code>, faire
Buddy code> hériter à partir de
animal code> et modifiez le paramètre de
sur code > Pour
Animal & Code>, vous avez une configuration dans laquelle tout animal peut voir tout autre animal.
La conception appelle spécifiquement à la reconnaissance de certaines entités afin d'exécuter certaines opérations sur eux. Parce qu'il n'y a pas de rime ni de raison en ce qui concerne la raison pour laquelle certaines opérations vont avec certaines entités (c'est-à-dire: c'est tout arbitraire), ce que vous envisagez d'envoyer une expédition ou une répartition basée sur la propriété. J'irais avec ce dernier. P>
Donnez à chaque entité un ensemble de propriétés. Le chien réagirait ainsi en fonction de ces propriétés. Le chat et l'écureuil auraient la propriété ", devait aboyer de chien." Lorsque le chien rencontre une entité avec une telle propriété, elle effectuerait l'action appropriée. P>
Dans ce cas, une entité n'est rien de plus que la somme de ses propriétés ainsi que les comportements basés sur la rencontre d'autres entités avec diverses propriétés. L'entité peut également avoir un état associé à un État. Il n'y aurait pas de chien ou de chat spécifique classe em>. Il y aurait juste une entité avec des propriétés et des comportements semblables à des chats et une entité avec des propriétés et des comportements semblables à des chiens. P>
Ceci est définitivement une bonne idée. C'est certainement une illustration de la raison pour laquelle OO n'est pas la fin - tous des paradigmes de programmation. Cependant, il convient probablement également d'apprendre à quel point OO «VRAI» résoudrait le problème, comme point de comparaison. De plus, la question est explicitement un exercice dans OO Design. (Cela suppose que vous définissez OO comme profitez du polymorphisme, non simplement comme une association de données et de fonctions qui fonctionnent sur ces données.)
@Johncalsbeek Je ne vois pas comment cela est en quelque sorte "pas oo". Même si je devais mettre en place un système de définition d'entité basé sur la propriété, j'utiliserais une conception OO pour y accomplir. Qu'est-ce que sur la Terre constitue "vrai oo" dans ce ou tout autre cas ?? J'ai même fini mon diplôme et je ne vois rien ici qui tombe en dehors de ce qui peut être accompli avec OOP.
@Thebuzzsaw: Ne pas parler pour John, mais personnellement, je ne considère pas un design "objet orienté" de conception, à moins que cela implique un polymorphisme par héritage. Sans cela, ce n'est rien que vous ne pouviez pas facilement faire dans C.
Oui. Il existe une distinction entre "une conception OO" et "une conception la plus naturellement mise en œuvre avec OO". OO Outils sont un grand marteau, et cela ressemble vraiment à un clou.
@Nicolbolas: Je suis respectueusement en désaccord. Le fait que le chien réagit aux écureuils soit particulièrement particulier à ce chien i>, pas aux écureuils. En ce qui concerne les dépendances, ceci est horrible.
@Matthiez.: Le design donné n'explique pas comment les autres chiens réagissent à ces choses. En outre, il n'y a rien dans ma suggestion qui exige que les propriétés et les comportements soient généraux à tous les chiens. C'est un système de composant, pas un système hiérarchique.
la plupart du temps, vous pouvez remplacer RTTI par la messagerie.
sorte de p> la messagerie est plus flexible que RTTI en principe: P> other_object->send(IS_SCARRY_OF, this);
Ce n'est rien de plus que RTTI basé sur le compilateur. C'est le même concept: les objets ont un identifiant qui déterminent leur type au moment de l'exécution.
@Nicol Bolas - non exactement, voir le texte à partir de "la messagerie est plus flexible ..." RTTI décrit un seul "message" - who_are_you en soi.
Ou vous pouvez simplement avoir une fonction appelée "is_scarrry_of" qui prend un objet. Tout ce que vous faites consiste à utiliser le message qui passe pour prendre la place de l'expédition virtuelle et RTTI. Et donc, perdre les caractéristiques de la langue et les garanties des deux.
Il existe un nombre ridiculement grand de façons de satisfaire ce problème à l'aide de "concepts OO", selon ce que vous voulez souligner.
Voici la solution la plus simple que je puisse proposer: p>
class Animal { public: virtual void visit(Visitor&) = 0; }; class Cat : public Animal { public: virtual void visit(Visitor& v) { v.visit(*this); } }; class Squirrel : public Animal { public: virtual void visit(Visitor& v) { v.visit(*this); } }; // classes for Frog, Coyote, Spot... class Visitor { public: virtual void visit(Cat&) = 0; virtual void visit(Squirrel&) = 0; // ... }; class BuddyVision : public Visitor { public: virtual void visit(Cat&) { /* ... */ } virtual void visit(Squirrel&) { /* ... */ } // ... }; class Buddy { public: void see(Animal& a) { BuddyVision visitor; a.visit(visitor); } };
Astuce: BuddyVision () code> ne peut pas être lié à une référence non-Const. Vous devez soit fournir une surcharge de
visiter code> ou l'instancier sur la pile comme argument nommé (oui, c'est stupide ...).
@John CalSbeek: Merci beaucoup !!
Je pense que cette question appartient à des programmeurs.stackexchange.com.
A Très B> Note importante est RTTI, comme manipulé par le compilateur i> n'est pas le seul moyen pour un objet de s'identifier. Vous pouvez également avoir un
Enum AnimalTypes Code> et
Animal virtuel :: gettype () Code> Méthode, ou un
UUID inconnu :: getclass () code> méthode (A La com 'code> iunknown :: QueryInterface CODE>) ou même un "code> animal spécifique à un problème :: isscareierthan (animal * me) code>. Il existe un certain nombre de façons d'utiliser la conception orientée objet pour obtenir des informations de type d'exécution, sans utiliser RTTI en tant que telle.
qui est venu visiter i> -> Vous voulez dire que le chat et l'écureuil sont visiteurs i>;)?