Devrais-je éviter d'utiliser l'héritage d'objets autant que possible pour développer un jeu?


36

Je préfère les fonctionnalités de POO lors du développement de jeux avec Unity. Je crée généralement une classe de base (principalement abstraite) et utilise l'héritage d'objet pour partager les mêmes fonctionnalités avec les autres objets.

Cependant, j'ai récemment entendu quelqu'un dire qu'il fallait éviter l'utilisation de l'héritage et utiliser plutôt des interfaces. Alors j'ai demandé pourquoi, et il a dit que "l'héritage d'objet est important bien sûr, mais s'il y a beaucoup d'objets étendus, les relations entre les classes sont profondément couplées.

J'utilise une classe de base abstraite, quelque chose comme WeaponBaseet la création de classes d'armes spécifiques comme Shotgun, AssaultRifle, Machinegunquelque chose comme ça. Il y a tellement d'avantages et l'un des motifs que j'apprécie vraiment est le polymorphisme. Je peux traiter l'objet créé par les sous-classes comme s'il s'agissait de la classe de base, de sorte que la logique puisse être considérablement réduite et rendue plus réutilisable. Si j'ai besoin d'accéder aux champs ou aux méthodes de la sous-classe, je renvoie à la sous-classe.

Je ne veux pas définir mêmes champs, couramment utilisés dans les différentes classes, comme AudioSource/ Rigidbody/ Animatoret beaucoup de champs membres comme je définis fireRate, damage, range, spreadet ainsi de suite. De plus, dans certains cas, certaines méthodes pourraient être écrasées. J'utilise donc des méthodes virtuelles dans ce cas, afin de pouvoir invoquer cette méthode à l'aide de la méthode de la classe parente, mais si la logique est différente dans child, je les ai remplacées manuellement.

Alors, faut-il que toutes ces choses soient abandonnées en tant que mauvaises pratiques? Devrais-je utiliser des interfaces à la place?


30
"Il y a tellement d'avantages, et l'un des motifs que j'apprécie vraiment est le polymorphisme." Le polymorphisme n'est pas un motif. C'est littéralement le but de la programmation orientée objet. D'autres choses, comme des champs communs, etc. peuvent être facilement réalisées sans duplication de code ni héritage.
Cubique

3
La personne qui vous a suggéré les interfaces était-elle meilleure que l'héritage vous a-t-elle donné des arguments? Je suis curieux.
Hawker65

1
@Cubic Je n'ai jamais dit que le polymorphisme est un motif. J'ai dit "... un motif que j'apprécie vraiment, c'est le polymorphisme". Cela signifie que le motif que j'apprécie vraiment utilise le "polymorphisme", et que le polymorphisme n'est pas un motif.
modernateur le

4
Les gens vantent les interfaces plutôt que l'héritage dans toutes les formes de développement. Cependant, cela a tendance à ajouter beaucoup de frais généraux, une dissonance cognitive, à une explosion de classe, à une valeur discutable et à une synergie insuffisante dans un système, à moins que TOUT LE MONDE ne se concentre sur les interfaces. Alors n'abandonnez pas pour l'instant l'héritage. Cependant, les jeux ont des caractéristiques uniques et l'architecture de Unity vous oblige à utiliser un paradigme de conception CES, raison pour laquelle vous devriez peaufiner votre approche. Lisez la série Wizards and Warriors d'Eric Lippert décrivant les problèmes liés au jeu.
Dunk

2
Je dirais qu'une interface est un cas particulier d'héritage où la classe de base ne contient aucun champ de données. Je pense que la suggestion est d'essayer de ne pas construire un énorme arbre où chaque objet doit être classé, mais plutôt un grand nombre de petits arbres basés sur des interfaces où vous pouvez tirer parti de l'héritage multiple. Le polymorphisme n'est pas perdu avec les interfaces.
Emanuele Paolini

Réponses:


65

Privilégiez la composition à l'héritage dans vos systèmes d'entité et d'inventaire / article. Ce conseil s’applique généralement aux structures de logique de jeu, lorsque la manière dont vous pouvez assembler des choses complexes (au moment de l’exécution) peut conduire à de nombreuses combinaisons différentes; c'est quand on préfère la composition.

Privilégiez l'héritage à la composition dans votre logique au niveau de l'application, des constructions d'interface utilisateur aux services. Par exemple,

Widget->Button->SpinnerButton ou

ConnectionManager->TCPConnectionManagervs ->UDPConnectionManager.

... il existe ici une hiérarchie de dérivation clairement définie, plutôt qu'une multitude de dérivations potentielles, de sorte qu'il est simplement plus facile d'utiliser l'héritage.

En bout de ligne : utilisez l'héritage où vous pouvez, mais utilisez la composition où vous le devez. PS L'autre raison pour laquelle nous pouvons favoriser la composition dans les systèmes d'entité est qu'il existe généralement de nombreuses entités et que l'héritage peut entraîner un coût de performance pour accéder aux membres de chaque objet. voir vtables .


10
L'héritage n'implique pas que toutes les méthodes seraient virtuelles. Cela ne conduit donc pas automatiquement à un coût de performance. VTable joue uniquement un rôle dans la répartition des appels virtuels et non dans l'accès aux membres de données.
Ruslan

1
@Ruslan J'ai ajouté les mots "may" et "can" pour répondre à vos commentaires. Sinon, afin de garder la réponse concise, je n’entre pas dans les détails. Merci.
Ingénieur

7
P.S. The other reason we may favour composition in entity systems is ... performance: Est-ce vraiment vrai? Si vous regardez la page WIkipedia liée par @Linaith, vous devez composer votre objet d’interfaces. Par conséquent, vous avez (encore ou même davantage) d'appels de fonction virtuels et plus de cache manquants, car vous avez introduit un autre niveau d'indirection.
Flamefire

1
@ Flamefire Oui, c'est vrai; il existe des moyens d'organiser vos données de manière à ce que l'efficacité de votre cache soit optimale, indépendamment de tout, et certainement beaucoup plus optimale que ces indirectes supplémentaires. Ce ne sont pas héritages et sont une composition, bien que relevant davantage du sens tableau-structure / structure-de tableaux (données entrelacées / non entrelacées dans un arrangement en cache-linéaire), scindées en tableaux séparés et parfois dupliquant des données pour faire correspondre des ensembles des opérations à différentes parties de votre pipeline. Mais encore une fois, entrer ici serait un détournement très important qu'il vaut mieux éviter pour des raisons de concision.
Ingénieur

2
N'oubliez pas de garder les commentaires aux demandes civiles de clarification ou de critique et de débattre du contenu des idées et non du caractère ou de l'expérience de la personne qui les exprime.
Josh

18

Vous avez déjà quelques bonnes réponses, mais l’énorme éléphant dans la pièce de votre question est celui-ci:

entendu quelqu'un dire qu'il faut éviter l'utilisation de l'héritage et utiliser plutôt des interfaces

En règle générale, lorsque quelqu'un vous donne une règle empirique, alors ignorez-la. Cela vaut non seulement pour "quelqu'un qui vous dit quelque chose", mais aussi pour lire des choses sur Internet. À moins que vous ne sachiez pourquoi (et que vous puissiez vraiment le supporter), un tel conseil est sans valeur et souvent très dangereux.

D'après mon expérience, les concepts les plus importants et les plus utiles de la programmation orientée objet sont "faible couplage" et "forte cohésion" (les classes / objets se connaissent le moins possible les uns sur les autres et chaque unité est responsable du moins de choses possible).

Faible couplage

Cela signifie que tout "paquet" de votre code doit dépendre le moins possible de son environnement. Cela vaut pour les classes (conception de classes) mais aussi pour les objets (implémentation réelle), les "fichiers" en général (c'est-à-dire le nombre de #includes par .cppfichier, le nombre de fichiers importpar .javafichier, etc.).

Un signe que deux entités sont couplées est que l'une d'entre elles va se briser (ou doit être modifiée) lorsque l'autre est modifiée de quelque manière que ce soit.

L'héritage augmente le couplage, évidemment; changer la classe de base change toutes les sous-classes.

Les interfaces réduisent le couplage: en définissant un contrat clair, basé sur une méthode, vous pouvez modifier librement tout ce qui concerne les deux côtés de l'interface, à condition de ne pas modifier le contrat. (Notez que "interface" est un concept général, le langage Javainterface classes abstraites ou C ++ ne sont que des détails d'implémentation).

Haute cohésion

Cela signifie que chaque classe, objet, fichier, etc. soit concerné ou responsable du moins possible. Autrement dit, évitez les grandes classes qui font beaucoup de choses. Dans votre exemple, si vos armes ont des aspects complètement séparés (munitions, comportement de tir, représentation graphique, représentation d'inventaire, etc.), vous pouvez avoir différentes classes qui représentent exactement l'une de ces choses. La classe d'arme principale se transforme alors en "détenteur" de ces détails; un objet d'arme n'est alors guère plus que quelques indications sur ces détails.

Dans cet exemple, vous vous assurez que votre classe représentant le "comportement de tir" en sait le moins possible sur la classe d'armes principale. De manière optimale, rien du tout. Cela signifierait, par exemple, que vous pourriez donner un "comportement de mise à feu" à n'importe quel objet de votre monde (tourelles, volcans, PNJ, etc.) en un claquement de doigt. Si, à un moment donné, vous souhaitez modifier la manière dont les armes sont représentées dans l'inventaire, vous pouvez simplement le faire - seule votre classe d'inventaire en est consciente.

Un signe qu'une entité n'est pas cohérente est qu'il grandit de plus en plus, se ramifiant dans plusieurs directions en même temps.

L'héritage tel que vous le décrivez diminue la cohésion. Vos classes d'armes sont, en fin de compte, de gros morceaux qui gèrent toutes sortes d'aspects différents et non liés de vos armes.

Les interfaces augmentent indirectement la cohésion en séparant clairement les responsabilités entre les deux côtés de l'interface.

Que faire maintenant

Il n'y a toujours pas de règles strictes, tout cela n'est que des directives. En général, comme l'utilisateur TKK l'a mentionné dans sa réponse, l'héritage est beaucoup enseigné à l'école et dans les livres; ce sont les choses fantaisistes sur la POO. Les interfaces sont probablement plus ennuyeuses à enseigner et aussi (si vous dépassez des exemples triviaux) un peu plus difficiles, ouvrant le champ de l'injection de dépendance, qui n'est pas aussi nette que l'héritage.

En fin de compte, votre système fondé sur l'héritage est toujours préférable à l'absence de conception claire de la POO. Alors n'hésitez pas à vous en tenir à cela. Si vous le souhaitez, vous pouvez réfléchir / google un peu sur le couplage faible, la cohésion élevée et voir si vous souhaitez ajouter ce type de réflexion à votre arsenal. Vous pouvez toujours refacturer pour essayer cela si vous le souhaitez, plus tard; ou essayez des approches basées sur une interface sur votre nouveau module de code plus grand.


Merci pour l'explication détaillée. C'est vraiment utile de comprendre ce qui me manque.
Modernator

13

L'idée qu'il faut éviter les héritages est tout simplement fausse.

Il existe un principe de codage appelé Composition sur l'héritage . Cela dit que vous pouvez réaliser les mêmes choses avec la composition, et c'est préférable, car vous pouvez réutiliser une partie du code. Voir Pourquoi devrais-je préférer la composition à l'héritage?

Je dois dire que j'aime vos classes d'armes et que cela se ferait de la même manière. Mais je n'ai pas encore créé de jeu ...

Comme l'a souligné James Trotter, la composition pourrait présenter certains avantages, notamment en termes de flexibilité lors de l'exécution pour modifier le fonctionnement de l'arme. Ce serait possible avec l'héritage, mais c'est plus difficile.


14
Plutôt que d'avoir des classes pour les armes, vous pouvez avoir une seule classe "arme" et des composants pour gérer ce que fait le tir, ses attachements et ce qu'ils font, son "stockage de munitions", vous pouvez créer de nombreuses configurations. , dont certains peuvent être un "fusil à pompe" ou un "fusil d'assaut", mais cela peut également être modifié au moment de l'exécution, par exemple pour déconnecter les pièces jointes et les capacités du chargeur, etc. Ou bien de nouvelles configurations d'armes à feu peuvent être créées Je n'ai même pas pensé à l'origine. Oui, vous pouvez obtenir quelque chose de similaire avec l'héritage, mais pas aussi facile.
Trotski94

3
@JamesTrotter À ce stade, je pense à Borderlands et à ses armes, et je me demande quelle monstruosité ce serait avec un seul héritage ...
Baldrickk

1
@JamesTrotter J'aimerais que ce soit une réponse et non un commentaire.
Pharap

6

Le problème est que l'héritage entraîne le couplage - vos objets doivent en savoir plus les uns sur les autres. C'est pourquoi la règle est "toujours privilégier la composition à l'héritage". Cela ne signifie pas que vous n'utiliserez JAMAIS l'héritage, mais que vous l'utiliserez là où c'est tout à fait approprié, mais si jamais vous vous assoyez en pensant: "Je peux le faire dans les deux sens et ils ont tous deux un sens", passez directement à la composition.

L'héritage peut aussi être un peu limitant. Vous avez un "WeaponBase" qui peut être un AssultRifle - génial. Que se passe-t-il lorsque vous avez un fusil à double canon et que vous voulez permettre à ceux-ci de tirer de manière indépendante - un peu plus difficile mais faisable, vous avez juste une classe à un et deux canons, mais vous ne pouvez pas simplement monter 2 canons sur le même pistolet, pouvez-vous? Pourriez-vous en modifier un pour avoir 3 barils ou avez-vous besoin d'une nouvelle classe pour cela?

Qu'en est-il d'un fusil d'assaut avec un GrenadeLauncher dessous - hmm, un peu plus difficile. Pouvez-vous remplacer le GrenadeLauncher par une lampe de poche pour la chasse nocturne?

Enfin, comment permettez-vous à votre utilisateur de créer les armes précédentes en modifiant un fichier de configuration? Cela est difficile car vous avez des relations codées en dur qui pourraient être mieux composées et configurées avec des données.

L'héritage multiple peut résoudre certains de ces exemples triviaux, mais il ajoute son propre ensemble de problèmes.

Avant qu'il y ait des dictons courants tels que "Préfère la composition à l'héritage", j'ai découvert ceci en écrivant un arbre d'héritage trop complexe (qui était génial et qui marchait parfaitement), puis en découvrant qu'il était très difficile de le modifier et de le conserver ultérieurement. Le dicton dit simplement que vous avez un moyen alternatif et compact d’apprendre et de vous souvenir d’un tel concept sans avoir à passer par toute l’expérience - mais si vous souhaitez utiliser l’héritage de manière intensive, je vous recommande de garder l’esprit ouvert et d’évaluer à quel point cela fonctionne. pour vous - rien de terrible ne se produira si vous utilisez fortement l'héritage et ce pourrait être une excellente expérience d'apprentissage au pire (au mieux, cela pourrait fonctionner correctement pour vous)


2
"comment permettez-vous à votre utilisateur de créer les armes précédentes en modifiant un fichier de configuration?" -> Le modèle que je fais généralement est de créer une classe finale pour chaque arme. Par exemple, comme Glock17. Créez d'abord la classe WeaponBase. Cette classe est abstraite et définit des valeurs communes telles que le mode de tir, la vitesse de tir, la taille du magasin, le nombre maximum de munitions et les pellets. En outre, il gère les entrées utilisateur, telles que mouse1 / mouse2 / reload et appelle la méthode correspondante. Elles sont presque virtuelles ou divisées en plusieurs fonctions afin que les développeurs puissent remplacer les fonctionnalités de base s’ils en avaient besoin. Et ensuite, créez une autre classe qui a étendu WeaponBase,
modernisateur le

2
quelque chose comme SlideStoppableWeapon. La plupart des pistolets ont cela, et cela gère des comportements supplémentaires tels que glisser arrêté. Enfin, créez la classe Glock17 qui s'étend à partir de SlideStoppableWeapon. Glock17 est la dernière classe, si le pistolet a une capacité unique qui n’a finalement été inscrite qu’ici. J'utilise habituellement ce modèle lorsque le pistolet a un mécanisme de tir spécial ou un mécanisme de rechargement. Appliquez ce comportement unique à la hiérarchie de fin de classe, combinez autant que possible les logiques courantes des parents.
Modernateur

2
@modernator Comme je l'ai dit, il ne s'agit que d'une ligne directrice - si vous n'y croyez pas, n'hésitez pas à l'ignorer, gardez l'œil ouvert sur les résultats au fil du temps et évaluez les avantages et les inconvénients de temps à autre. J'essaie de me souvenir des endroits où j'ai écrasé mes orteils et j'aide les autres à éviter la même chose, mais ce qui fonctionne pour moi peut ne pas fonctionner pour vous.
Bill K

7
@modernator Dans Minecraft, ils ont créé Monsterune sous-classe de WalkingEntity. Puis ils ont ajouté des boues. À quel point pensez-vous que cela a fonctionné?
user253751

1
@immibis Avez-vous une référence ou un lien anecdotique à ce problème? Googler mots - clés minecraft me noie dans les liens vidéo ;-)
Peter - Réintégrer Monica

3

Contrairement aux autres réponses, cela n'a rien à voir avec l'héritage ou la composition. L'héritage par rapport à la composition est une décision que vous prenez concernant la manière dont une classe sera mise en œuvre. Les interfaces contre les classes est une décision qui précède.

Les interfaces sont les citoyens de première classe de toutes les langues POO. Les classes sont des détails d'implémentation secondaires. Les enseignants et les livres qui introduisent les classes et l'héritage avant les interfaces déforment gravement l'esprit des nouveaux programmeurs.

Le principe clé est que, chaque fois que cela est possible, les types de tous les paramètres de méthode et les valeurs de retour doivent être des interfaces et non des classes. Cela rend vos API beaucoup plus flexibles et puissants. La plupart du temps, vos méthodes et leurs appelants ne doivent avoir aucune raison de connaître ou de ne pas se soucier des classes réelles des objets avec lesquels ils traitent. Si votre API est agnostique à propos des détails d'implémentation, vous pouvez librement basculer entre composition et héritage sans rien casser.


Si les interfaces sont les citoyens de première classe de n'importe quel langage POO, je me demande si Python, Ruby,… ne sont pas des langages OOP.
BlackJack

@BlackJack: En Ruby, l'interface est implicite (dactylographie si vous voulez), et exprimée en utilisant la composition au lieu de l'héritage (aussi, il y a des Mixins qui sont quelque part entre, à mon avis) ...
AnoE

@BlackJack "Interface" (le concept) ne nécessite pas interface(le mot-clé du langage).
Caleth

2
@ Caleth Mais en les appelant des citoyens de première classe, c'est à mon humble avis . Quand une description de langue prétend que quelque chose est un citoyen de première classe, cela signifie généralement que c'est une chose réelle dans cette langue qui a un type et une valeur et qui peut être transmise. Les classes Like sont des citoyens de première classe en Python, au même titre que les fonctions, les méthodes et les modules. Si nous parlons du concept, les interfaces font également partie de tous les langages non-POO.
BlackJack

2

Chaque fois que quelqu'un vous dit qu'une approche spécifique est la meilleure pour tous les cas, c'est la même chose que de vous dire qu'un seul et même médicament guérit toutes les maladies.

Héritage vs composition est une question est-a vs has-a. Les interfaces sont un autre moyen (3ème) approprié à certaines situations.

L'héritage, ou la logique is-a: vous l'utilisez quand la nouvelle classe va se comporter et être utilisé complètement comme (extérieurement) l'ancienne classe dont vous dérivez, si la nouvelle classe va exposer au public toutes les fonctionnalités que l'ancienne classe avait ... alors vous héritez.

Composition ou logique du has-a: si la nouvelle classe a juste besoin d'utiliser en interne l'ancienne classe sans exposer les fonctionnalités de l'ancienne classe au public, vous utilisez la composition, c'est-à-dire que vous avez une instance de l'ancienne classe propriété membre ou une variable de la nouvelle. (Cela peut être une propriété privée, ou protégée, ou autre, selon le cas d'utilisation). Le point clé ici est qu'il s'agit du cas d'utilisation dans lequel vous ne souhaitez pas exposer les fonctionnalités de classe d'origine et les utiliser pour le public, mais les utiliser en interne, alors que dans le cas d'héritage, vous les exposez au public, via le nouvelle classe. Parfois, vous avez besoin d'une approche et parfois de l'autre.

Interfaces: les interfaces constituent un autre cas d'utilisation - lorsque vous souhaitez que la nouvelle classe implémente partiellement et non complètement et n'expose pas au public les fonctionnalités de l'ancienne. Cela vous permet d’avoir une nouvelle classe, une classe d’une hiérarchie totalement différente de l’ancienne, se comporte comme l’ancienne sous certains aspects seulement.

Supposons que vous avez un assortiment de créatures représentées par des classes et que leurs fonctionnalités sont représentées par des fonctions. Par exemple, un oiseau aurait Talk (), Fly () et Merde (). La classe Canard hériterait de la classe Bird, mettant en œuvre toutes les fonctionnalités.

La classe Fox, évidemment, ne peut pas voler. Donc, si vous définissez l'ancêtre comme ayant toutes les fonctionnalités, vous ne pouvez pas dériver le descendant correctement.

Si, toutefois, vous divisez les entités en groupes, représentant chaque groupe d'appels avec une interface, par exemple, IFly, contenant Takeoff (), FlapWings () et Land (), vous pouvez pour la classe Fox implémenter des fonctions à partir de ITalk et IPoop. mais pas IFly. Vous définissez ensuite les variables et les paramètres pour accepter les objets qui implémentent une interface spécifique, puis le code qui les utilise sait ce qu’il peut appeler ... et peut toujours rechercher d’autres interfaces, s’il doit voir si d’autres fonctionnalités le sont également. mis en œuvre pour l'objet actuel.

Chacune de ces approches a des cas d'utilisation quand c'est la meilleure, aucune approche n'est la meilleure solution absolue pour tous les cas.


1

Pour un jeu, en particulier avec Unity, qui fonctionne avec une architecture à composants d'entités, vous devez privilégier la composition plutôt que l'héritage pour vos composants de jeu. Il est beaucoup plus flexible et évite de tomber dans une situation où vous souhaitez qu'une entité de jeu «soit» deux éléments situés sur des feuilles différentes d'un arbre d'héritage.

Supposons, par exemple, que vous avez une TalkingAI sur une branche d’un arbre d’héritage, et que VolumetricCloud se trouve sur une autre branche distincte et que vous souhaitez un nuage parlant. C'est difficile avec un arbre d'héritage profond. Avec entité-composant, vous créez simplement une entité qui comporte des composants TalkingAI et Cloud, et vous êtes prêt à partir.

Mais cela ne signifie pas que, par exemple, dans votre implémentation de nuage volumétrique, vous ne devriez pas utiliser l'héritage. Le code correspondant peut être substantiel et se composer de plusieurs classes. Vous pouvez utiliser OOP selon vos besoins. Mais tout cela équivaudra à une seule composante du jeu.

En note de bas de page, je ne suis pas d'accord avec ceci:

Je crée généralement une classe de base (principalement abstraite) et utilise l'héritage d'objet pour partager les mêmes fonctionnalités avec les autres objets.

L'héritage n'est pas destiné à la réutilisation de code. C'est pour établir une relation is-a . Souvent, cela va de pair, mais il faut faire attention. Le fait que deux modules aient besoin d'utiliser le même code ne signifie pas que l'un est du même type que l'autre.

Vous pouvez utiliser des interfaces si vous voulez avoir, par exemple, List<IWeapon>différents types d’armes. De cette manière, vous pouvez hériter de l'interface IWeapon et de la sous-classe MonoBehaviour pour toutes les armes et éviter tout problème lié à l'absence d'héritage multiple.


-3

Vous semblez ne pas comprendre ce qu'une interface est ou fait. Il m'a fallu environ 10 ans de réflexion sur OO et poser des questions à des personnes très intelligentes pour savoir si je pouvais avoir un moment ah-ha avec des interfaces. J'espère que cela t'aides.

Le mieux est d’en utiliser une combinaison. Dans mon esprit, modéliser le monde et les gens, disons un exemple profond. L'âme est interfacée avec le corps à travers l'esprit. Le mental EST l'interface entre l'âme (certains considèrent l'intellect) et les ordres donnés au corps. L'interface des esprits avec le corps est la même pour toutes les personnes, fonctionnellement parlant.

La même analogie peut être utilisée entre la personne (corps et âme) en interface avec le monde. Le corps est l'interface entre l'esprit et le monde. Tout le monde s'interface de la même manière avec le monde. La seule particularité est la façon dont nous interagissons avec le monde. C'est ainsi que nous utilisons notre esprit pour décider comment nous interagissons / interagissons dans le monde.

Une interface est alors simplement un mécanisme permettant de relier votre structure OO à une autre structure OO différente, chaque côté ayant des attributs différents qui doivent être négociés / mappés les uns aux autres pour produire une sortie fonctionnelle dans un milieu / environnement différent.

Donc, pour que l'esprit appelle la fonction open-hand, il doit implémenter l'interface nerveuse_command_system avec QUE, ayant sa propre API avec des instructions sur la manière de mettre en œuvre toutes les exigences nécessaires avant d'appeler open-hand.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.