7
votes

OOP DESIGN - Beaucoup d'objets avec des interactions uniques au sous-ensemble limité des autres

Si la classe A a une interaction unique avec chacune des classes B, C et D, si le code de l'interaction soit dans A ou en B, C et D?

J'écris un petit jeu par lequel de nombreux objets peuvent avoir des interactions uniques avec d'autres objets. Par exemple, un EMP hits a pistolet sentinelle et le désactive. Il pourrait également frapper un grenade et le détoner, il pourrait également appuyer sur un lecteur et d'appliquer un effet de ralentissement.

Ma question est que ce code devrait-il aller dans la classe EMP ou être diffusée parmi toutes les autres classes? Mon intestin me dit de faire cela polymorphiquement pour que je dise simplement à chaque classe de faire face à la frappe EMP mais elle aime, ce qui me permettrait d'ajouter plus d'articles et de modifier la manière dont ils traitent avec l'EMP sans changer le code EMP.

Cependant, l'EMP n'interagit actuellement qu'à environ 4 sur 50 de mes objets, afin de remplir 46 objets avec des appels de réponse vides de réponse () semble faux. Il semble également un peu intuitif, si je décide de supprimer le PEM, je dois changer toutes les catégories et la classe EMP se termine assez minuscule. Cela signifie également si je veux modifier la manière dont le PEM est comportant, je dois aller chercher à travers toutes les différentes classes pour trouver tous les usages possibles. De plus, si l'EMP a des effets génériques tels qu'une explosion, cet effet serait certainement à l'intérieur du code EMP, à l'abri de tous les autres effets qui seraient distribués.


2 commentaires

Vous n'avez pas mentionné quel langage de programmation que vous utilisez, mais cela ressemble à un cas d'utilisation parfait pour un protocole (dans l'objectif-c) ou une interface (en Java). Ensuite, lorsque votre EMP le détonate, vous pouvez vérifier si les objets situés dans la plage sont conformes au protocole et appelez une méthode de protocole si elle le fait.


Il serait également bon d'avoir une classe centrale pour gérer ces interactions. C'est à dire. Une classe "interaction" avec une méthode appelée à chaque fois qu'une action pouvant entraîner des interactions. Ensuite, vous pouvez faire boucle à travers tous les objets "dans la gamme" et dire si l'action est EMP et la cible est conforme au protocole EMP, envoyez ensuite un message EMP_Détonated à la cible . De cette façon, lorsque vous ajoutez de nouvelles interactions, tout le code est au même endroit et que vous n'ayez implémenter que le protocole dans les classes où il convient.


5 Réponses :


1
votes

Mes pensées seraient que pistolet Sentry , grenade et lecteur doit tous mettre en œuvre une interface commune qui applique la méthode réponse . De cette façon, si vous décidez plus tard que l'un de vos 46 autres objets peut être touché par un EMP, vous saurez mettre en œuvre cette interface.


5 commentaires

OK, alors j'ai 3 objets qui implémentent l'interface et 47 objets qui ne le font pas. Lorsque mon EMP explose, je sais qu'il a frappé certains objets, comment puis-je savoir si l'objet qu'il a frappé a mis en œuvre cette interface ou non?


Je ne suis pas sûr de comprendre la question, mais vous devriez pouvoir utiliser Réflexion Pour cela. Toute la logique concernant le "HIT" serait traitée dans la classe mettant en œuvre l'interface.


Permettez-moi de clarifier - mon EMP explose et le moteur me donne une liste d'entités que l'EMP a frappé. Seule une minorité de ces entités doit interagir avec l'EMP. Vous dites donc de vérifier chaque objet si cet objet implémente une interface à l'aide de la réflexion, puis appelant cette fonction de classe si elle le fait? Ne vérifiez-vous pas efficacement les types pour changer la logique, fondamentalement, le contraire de ce que le polymorphisme est censé accomplir?


Pourquoi auriez-vous besoin de savoir quels objets implémentent l'interface? Les objets qui mettent en œuvre cela feraient tout ce qu'ils sont censés faire lorsque EMP explose (car ils sont souscrits à l'événement EMP Exleded) et si un autre code doit savoir sur ce que ces objets ont fait lorsque EMP a explosé, vous pouvez soit mettre en œuvre un rappel ou publier. Un événement Autre code peut abonner à ...


C'est ce que je suggérais dans mon commentaire ci-dessus. Ce n'est pas le contraire du polymorphisme car vous vérifiez si un objet générique implémente une interface (ou est conforme à un protocole, en fonction de votre langue). Vous ne vous souciez pas de ce que l'objet est, juste s'il veut ou non vous parler.



0
votes

Ce n'est pas la solution la plus élégante, mais une chose que vous pourriez faire est d'avoir une classe de base que vos objets étendent avoir un comportement par défaut pour un événement et que des objets pourraient le remplacer s'il y avait quelque chose à faire.


0 commentaires


1
votes

Vous avez raison, avoir une méthode factice est une odeur de code. Il y a quelques façons de contourner ce problème:

Switchsnsements pour gérer les événements forts> fonctionne bien si vous vous attendez à ajouter plus d'objets car vous éviterez de modifier les événements lorsque vous ajoutez plus d'objets: P>

class EMP {
    void hit(SentryGun object) {
        object.disable();
    }

    void hit(Grenade object) {
        object.detonate();
    }
}


1 commentaires

C'est un peu déroutant des événements mentionnant lorsque vous ne parlez pas à ce que la plupart des gens envisagent des événements (motif d'observateur et / ou événements .net). Ce que vous faites ici, créez-vous efficacement une énumération pour représenter des types de classe, puis l'allumez-la, ce qui semble tout aussi mauvais que de jeter l'objet et de vérifier NULL. Chaque fois que vous créez une nouvelle classe, vous devez mettre à jour votre liste d'énumération que dépendent des deux côtés. Au moins avec une coulée, vous ne pouvez pas oublier cette étape supplémentaire. Dans votre deuxième exemple, vous supposez que vous avez déjà lancé l'objet, et tous les problèmes que j'ai décrits dans ma question s'appliquent toujours.



0
votes

3 commentaires

Idée intéressante, mais cela ne va-t-il pas éventuellement avoir le même code pour les objets de typeChecking et la logique de commutation en fonction du résultat? I.E. si (source est EMP && cible est SENTRUGUN) Désactiver () ? Ou si j'appelle une fonction spécifique EMP: si (cible est SENTRYGUN) désactiver () . Dans ce cas, je peux aussi bien mettre le code dans l'EMP: si (cible est Sentrygun) désactiver () .


Oui et non;) Dans ce cas, votre commande pourrait avoir une fonction DO_COMMAND (chose, objet) -> vide ou statut. Je ne sais pas s'il est indiqué sur le type de chèque comme si vous avez créé cette carte / table, vous devez disposer de la garantie de type correct - de sorte que vous venez d'obtenir des objets baissés aux types attendus. No si ou commutateur . Avantage est que vous pouvez facilement changer de comportement - par exemple lorsque le réglage du jeu passe en différentes plantes que l'EMP pourrait ne pas fonctionner sur quoi que ce soit - vous utilisez simplement une table différente ou modifiez-en existant. Vous séparez cette définition d'action des objets impliqués.


Correction: Vous séparez les objets Définition des actions. Aussi je voulais dire planète - pas planter ...