Je conçois mon propre petit programme OOP pour simuler les vampires, les loups, les humains et les camions et j'essaie de mettre en œuvre ma propre compréhension limitée des interfaces.
( Je suis encore en train de résumer ici et je n'ai pas encore d'implémentation de code, donc c'est plutôt une question de conception OOP ... Je pense!)
Ai-je raison de rechercher un «comportement commun» entre ces classes et de les implémenter en tant qu'interfaces ?
Par exemple, les vampires et les loups mordent ... alors devrais-je avoir une interface de morsure?
public class Vampire : Villain, IBite, IMove, IAttack
De même pour les camions ...
public class Truck : Vehicle, IMove
Et pour les humains ...
public class Man : Human, IMove, IDead
Est-ce que je pense ici? (Apprécier ton aide)
object-oriented
interfaces
user3396486
la source
la source
IEnumerable
,IEquatable
, etc.Réponses:
En général, vous voulez avoir des interfaces pour les caractéristiques communes de votre classe.
Je suis à moitié d'accord avec @Robert Harvey dans les commentaires, qui a dit que les interfaces représentent généralement des caractéristiques plus abstraites des classes. Néanmoins, je trouve à partir d'exemples plus concrets une bonne façon de commencer à penser abstrait.
Bien que votre exemple soit techniquement correct (c'est-à-dire oui, les vampires et les loups mordent, vous pouvez donc avoir une interface pour cela), il y a une question de pertinence. Chaque objet a des milliers de caractéristiques (par exemple, les animaux peuvent avoir de la fourrure, nager, grimper aux arbres, etc.). Allez-vous créer une interface pour chacun d'eux? Très peu probable.
Vous voulez généralement que les interfaces pour les choses qui ont du sens soient regroupées dans une application dans son ensemble. Par exemple, si vous construisez un jeu, vous pouvez avoir un tableau d'objets IMove et mettre à jour leur position. Si vous ne voulez pas faire cela, avoir l'interface IMove est assez inutile.
Le fait est, ne faites pas trop d'ingénieur. Vous devez penser à comment allez-vous utiliser cette interface, et 2 classes ayant une méthode en commun ne sont pas une raison suffisante pour créer une interface.
la source
IBite
n'est pas particulièrement utile, mais vous voudrez peut-être queIAttack
vous puissiez travailler sur toutes les choses qui font des attaques, ouIUpdate
que vous puissiez exécuter les mises à jour pour tout, ouIPhysicsEnabled
que vous puissiez leur appliquer de la physique, etc.On dirait que vous créez un tas d' interfaces de méthode unique . C'est très bien à première vue, mais gardez à l'esprit que les interfaces n'appartiennent pas aux classes qui les implémentent. Ils appartiennent aux clients qui les utilisent. Les clients décident si quelque chose doit être quelque chose qui peut bouger et attaquer.
Si j'ai une
Combat
classe avec unefight()
méthode, cette méthode a probablement besoin d'appeler les deuxmove()
etattack()
sur le même objet. Cela suggère fortement la nécessité d'uneICombatant
interfacefight()
pouvant appelermove()
etattack()
passer. C'est plus propre que defight()
prendre unIAttack
objet et de le lancerIMove
pour voir s'il peut également bouger.Cela ne signifie pas que vous ne pouvez pas également avoir d'
IMove
IAttack
interfaces. J'espère juste que vous ne les faites pas sans qu'un client en ait besoin. Inversement, si aucun client n'a besoin de faire bouger et d'attaquer un objet,ICombatant
n'est pas nécessaire.Cette façon simple de regarder les interfaces est souvent perdue car les gens aiment les exemples suivants. Les premières interfaces auxquelles nous sommes exposés se trouvent dans les bibliothèques. Malheureusement, les bibliothèques n'ont aucune idée de ce que sont leurs clients. Ils ne peuvent donc que deviner les besoins de leurs clients. Pas le meilleur exemple à suivre.
la source
Demandez-vous s'il sera courant d'avoir des collections d'objets avec différentes combinaisons de capacités, et si le code peut vouloir exécuter une action sur les éléments, dans une collection, qui le prennent en charge . Si c'est le cas, et s'il y aurait un "comportement par défaut" sensible pour les objets qui n'ont pas de support utile pour une action, il peut être utile d'avoir des interfaces implémentées par un large éventail de classes, pas seulement celles qui peuvent se comporter utilement.
Par exemple, supposons que seuls quelques types de créatures peuvent avoir des Woozles, et on veut que ces créatures aient une
NumerOfWoozles
propriété. Si une telle propriété se trouvait dans une interface qui n'était implémentée que par des créatures pouvant avoir des Woozles, alors le code qui voulait trouver le nombre total de Woozles détenus par une collection de créatures de types mixtes devrait dire quelque chose comme:Si, cependant, WoozleCount était membre de Creature / ICreature, même si peu de sous-types remplaceraient l'implémentation par défaut de WoozleCount de Creature qui renvoie toujours zéro, le code pourrait être simplifié pour:
Bien que certaines personnes puissent s'irriter à l'idée que chaque créature implémente une propriété WoozleCount qui n'est vraiment utile que pour quelques sous-types, la propriété aurait un sens pour tous les types, qu'elle soit utile ou non avec des éléments connus pour être de ces types, et je considérerais l'interface "évier de cuisine" comme étant moins une odeur de code que l'opérateur trycast.
la source