Je pense actuellement à une interface avec une classe que j'écris. Cette classe contient des styles pour un caractère, par exemple si le caractère est en gras, en italique, souligné, etc. Je discute avec moi-même depuis deux jours si je dois utiliser des getters / setters ou des noms logiques pour les méthodes qui changent les valeurs en ces styles. Bien que j'ai tendance à préférer les noms logiques, cela signifie écrire du code qui n'est pas aussi efficace et pas aussi logique. Laisse moi te donner un exemple.
J'ai une classe CharacterStyles
qui a des variables membres bold
, italic
, underline
(et quelques autres, mais je vais les laisser garder les choses simples). La façon la plus simple d'autoriser d'autres parties du programme à accéder à ces variables serait d'écrire des méthodes getter / setter, afin que vous puissiez faire styles.setBold(true)
et styles.setItalic(false)
.
Mais je n'aime pas ça. Non seulement parce que beaucoup de gens disent que les getters / setters cassent l'encapsulation (est-ce vraiment si mauvais?), Mais surtout parce que cela ne me semble pas logique. Je m'attends à styliser un personnage à travers une méthode, styles.format("bold", true)
ou quelque chose comme ça, mais pas à travers toutes ces méthodes.
Mais il y a un problème. Étant donné que vous ne pouvez pas accéder à une variable membre d'objet par le contenu d'une chaîne en C ++, je devrais soit écrire un grand conteneur d'instructions if / switch pour tous les styles, soit je devrais stocker les styles dans un tableau associatif ( carte).
Je ne peux pas comprendre quelle est la meilleure façon. Un instant, je pense que je devrais écrire les getters / setters, et l'instant suivant, je me penche dans l'autre sens. Ma question est: que feriez-vous? Et pourquoi feriez-vous ça?
la source
bold
set totrue
et que les autres variables ne sont pas définies, les méthodes getter pour les autres variables doivent renvoyer la valeur du style parent (qui est stocké dans une autre propriété), tandis que le getter de labold
propriété doit retournertrue
. Il y a d'autres choses comme un nom et la façon dont il s'affiche également dans l'interface.Réponses:
Oui, les getters / setters cassent l'encapsulation - ils ne sont fondamentalement qu'une couche supplémentaire entre l'accès direct au champ sous-jacent. Vous pourriez tout aussi bien y accéder directement.
Maintenant, si vous voulez que des méthodes plus complexes accèdent au champ, c'est valide, mais au lieu d'exposer le champ, vous devez réfléchir aux méthodes que la classe devrait offrir à la place. c'est à dire. au lieu d'une classe Bank avec une valeur Money exposée à l'aide d'une propriété, vous devez réfléchir aux types d'accès qu'un objet Bank devrait offrir (ajouter de l'argent, retirer, obtenir un solde) et les implémenter à la place. Une propriété sur la variable Money est uniquement syntaxiquement différente de l'exposition directe de la variable Money.
DrDobbs a un article qui en dit plus.
Pour votre problème, j'aurais 2 méthodes setStyle et clearStyle (ou autre) qui prennent une énumération des styles possibles. Une instruction switch à l'intérieur de ces méthodes appliquerait alors les valeurs pertinentes aux variables de classe appropriées. De cette façon, vous pouvez changer la représentation interne des styles en quelque chose d'autre si vous décidez plus tard de les stocker sous forme de chaîne (pour une utilisation en HTML par exemple) - quelque chose qui nécessiterait que tous les utilisateurs de votre classe soient également modifiés si vous utilisiez obtenir / définir les propriétés.
Vous pouvez toujours activer des chaînes si vous souhaitez prendre des valeurs arbitraires, soit avoir une grande instruction if-then (s'il y en a quelques-unes), soit une mappe de valeurs de chaîne vers des pointeurs de méthode à l'aide de std :: mem_fun (ou std :: fonction "donc" en gras "serait stocké dans une clé de carte avec sa valeur étant un sts :: mem_fun à une méthode qui définit la variable en gras sur vrai (si les chaînes sont les mêmes que les noms des variables membres, alors vous pouvez également utiliser la macro de chaîne pour réduire la quantité de code que vous devez écrire)
la source
styles.setStyle(BOLD, true)
? Est-ce exact?styles.getStyle(BOLD)
-vous lorsque vous avez non seulement des variables membres de type booléen, mais aussi de types entier et chaîne (par exemple:)styles.getStyle(FONTSIZE)
. Comme vous ne pouvez pas surcharger les types de retour, comment programmez-vous cela? Je sais que vous pourriez utiliser des pointeurs vides, mais cela me semble être un très mauvais moyen. Avez-vous des conseils sur la façon de procéder?Une idée que vous n'avez peut-être pas envisagée est le motif de décoration . Plutôt que de définir des indicateurs dans un objet, puis d'appliquer ces indicateurs à tout ce que vous écrivez, vous encapsulez la classe qui effectue l'écriture dans Decorators, qui à son tour applique les styles.
Le code appelant n'a pas besoin de savoir combien de ces wrappers vous avez mis autour de votre texte, vous appelez simplement une méthode sur l'objet externe et il appelle la pile.
Pour un exemple de pseudocode:
Et ainsi de suite, pour chaque style de décoration. Dans son utilisation la plus simple, vous pouvez alors dire
Et le code qui appelle cette méthode n'a pas besoin de connaître le détail de ce qu'elle reçoit. Tant que c'est QUELQUE CHOSE qui peut dessiner du texte via une méthode WriteString.
la source
TextWriter
faut parler aux deuxBoldDecorator
etItalicDecorator
(dans les deux sens) pour faire le travail.Je pencherais pour la deuxième solution. Il semble plus élégant et flexible. Bien qu'il soit difficile d'imaginer d'autres types que gras, italique et souligné (overline?), Il serait difficile d'ajouter de nouveaux types à l'aide de variables membres.
J'ai utilisé cette approche dans l'un de mes derniers projets. J'ai une classe qui peut avoir plusieurs attributs booléens. Le nombre et les noms des attributs peuvent changer dans le temps. Je les stocke dans un dictionnaire. Si un attribut n'est pas présent, je suppose que sa valeur est "false". Je dois également stocker une liste de noms d'attributs disponibles, mais c'est une autre histoire.
la source
Je pense que vous pensez trop à la question.
styles.setBold(true)
etstyles.setItalic(false)
sont OKla source