J'écris une application pour composer des freizes musicaux, mais je m'inquiète un peu de la structure des classes et des interfaces au sein du code. Ici, il y a les signatures de quelques classes I écrivaient:Comment écrire un code clair et élégant pour une application basée sur un modèle de stratégie?
Interface IGuidoFormattable
Class Note : IGuidoFormattable, ICloneable
Class Pause : IGuidoFormattable, ICloneable
Class Chord : List<Note>, IGuidoFormattable, ICloneable
Class Key : IGuidoFormattable, ICloneable
Class Tempo : IGuidoFormattable, ICloneable
Class Meter : IGuidoFormattable, ICloneable
Class FretPiece : List<IGuidoFormattable>, ICloneable
Class Fret : List<FretPiece>
FretPiece représente une phrase muscial, un morceau de la freize complète. Il expose comme propriétés Key, Tempo et Meter, qui sont homonymes avec leurs types. Plus de phrases réunies créent un freize, représenté par la classe Fret. Chaque élément dans une seule expression doit être formatable conformément à la notation standard GUIDO, par conséquent, il doit implémenter l'interface IGuidoFormattable. Dans un autre espace de noms, certaines classes de mutation sont définis et ils héritent tous d'une des deux classes abstraites:
Class FretMutation
Class LambdaFretMutation : FretMutation
Enfin, il existe une classe appelée FretMutationGenerator qui a la seule tâche d'appliquer des mutations sélectionnées sur un thème musical et affiche la totalité de freize en tant qu'instance de la classe Fret. FretPiece doit pouvoir contenir plusieurs éléments différents (notes, pauses et accords dans ce cas), qui doivent néanmoins satisfaire à deux contraintes: ils doivent être formatables avec la notation GUIDO et donc transformés en chaînes significatives; ils doivent être clonables. Dans le code tel qu'il est maintenant, chaque classe implémente ICloneable, mais la syntaxe et la sémantique du code actuel ne permettent pas de cloner tous les membres de la collection. J'ai besoin de trouver un moyen d'exprimer les deux contraintes sans appliquer d'héritage à IGuidoFormattable et de préférence sans définir de méthode Clone dans l'interface IGuidoFormattable.
Deuxièmement, et le plus important, le problème. FretMutation définit une méthode abstraite, "Apply", qui doit être surchargée dans chaque classe dérivée. Par conséquent, toute classe de mutation définit sa propre version de cette méthode, qui a la signature suivante:
FretPiece Apply(FretPiece originalTheme)
Il accepte en entrée un FretPiece et envoie une copie de cet objet, muté selon tous les autres paramètres spécifiés en tant que membres de la classe. Je pense que c'est une implémentation du modèle de stratégie. Cependant, seulement du fait que cette méthode crée une copie de l'entrée, cela signifie que l'argument lui-même (et donc tous ses membres) doit être clonable. En outre, FretPiece est déclaré comme une liste de IGuidoFormattable, mais chaque classe de mutation se comporte différemment des autres et peut agir sur des notes, des pauses ou des accords en conséquence: cela signifie que je dois vérifier le type de chaque élément et écrire un code différent pour chaque type avec "beaucoup" (en effet, 3 au plus) si déclarations. Et cela me semble très peu orienté objet.
Comment puis-je organiser les classes et l'interface de sorte que tous deviennent plus orientés objet et moins dépendants des hypothèses et des vérifications de type?
Répondre correctement à cette question nécessite de comprendre comment ces types sont tous connectés (c'est-à-dire, un accord est simplement un ensemble de notes, etc.). Avez-vous regardé l'utilisation de [GUIDOLib] (http://guidolib.sourceforge.net/) (C++)? À tout le moins, vous pourriez être capable de l'utiliser pour voir comment organiser vos classes. – Justin
Je ne peux pas lire de musique mais je pense qu'il y a d'énormes différences conceptuelles entre les notes, la pause, les accords et le tempo (je n'ai aucune idée de ce qu'une clé pourrait être). ce contenu. Donc un nœud peut être influencé par le tempo mais pas le tempo lui-même ne peut pas être influencé par une note. Je crois que vous devriez repenser un peu la structure de votre classe pour refléter cela. – Glenner003
Vous avez peut-être mal compris ce que je voulais dire, puisque j'ai intentionnellement fourni presque aucun code. Tempo spécifie le nombre de battements par minute et la durée digure qui représente un temps. La clé est la tonalité de la composition (ex: C Major, G Minor, ...). Meter indique la signature temporelle. Meter, Tempo et Key sont des propriétés de la classe FretPiece, représentant une phrase musicale. Les notes, les pauses et les accords sont des éléments de cette phrase. Un accord est ici représenté comme une simple liste de notes. Toutes les fonctions de formatage en notation GUIDO et de conversion en fichier MIDI sont déjà écrites. – Totem