Ich denke gerade über eine Schnittstelle zu einer Klasse nach, die ich schreibe. Diese Klasse enthält Stile für ein Zeichen, zum Beispiel, ob das Zeichen fett, kursiv, unterstrichen usw. ist. Ich habe zwei Tage lang mit mir selbst diskutiert, ob ich für die Methoden, die die Werte in ändern, Getter / Setter oder logische Namen verwenden soll diese Stile. Ich bevorzuge zwar logische Namen, aber es bedeutet, Code zu schreiben, der nicht so effizient und nicht so logisch ist. Lassen Sie mich Ihnen ein Beispiel geben.
Ich habe eine Klasse bekam CharacterStyles
die Membervariablen hat bold
, italic
, underline
(und einige andere, aber ich werde sie auslassen es einfach zu halten). Die einfachste Möglichkeit, anderen Programmteilen den Zugriff auf diese Variablen zu ermöglichen, besteht darin, Get- / Setter-Methoden zu schreiben, damit Sie styles.setBold(true)
und ausführen können styles.setItalic(false)
.
Aber das gefällt mir nicht. Nicht nur, weil viele Leute sagen, dass Getter / Setter die Kapselung sprengen (ist das wirklich so schlimm?), Sondern vor allem, weil es mir nicht logisch erscheint. Ich erwarte, einen Charakter mit einer styles.format("bold", true)
oder einer ähnlichen Methode zu stylen, aber nicht mit all diesen Methoden.
Es gibt jedoch ein Problem. Da Sie in C ++ nicht über den Inhalt eines Strings auf eine Objektelementvariable zugreifen können, müsste ich entweder einen großen if-Anweisungs- / switch-Container für alle Stile schreiben oder die Stile in einem assoziativen Array speichern ( Karte).
Ich kann nicht herausfinden, was der beste Weg ist. In einem Moment denke ich, ich sollte die Getter / Setter schreiben, und im nächsten Moment beuge ich mich in die andere Richtung. Meine Frage ist: Was würdest du tun? Und warum würdest du das tun?
quelle
bold
set totrue
und den anderen Variablen undefined habe, sollten die Getter-Methoden für die anderen Variablen den Wert des übergeordneten Stils (der in einer anderen Eigenschaft gespeichert ist) zurückgeben, während der Getter für diebold
Eigenschaft zurückgeben solltetrue
. Es gibt noch einige andere Dinge wie einen Namen und die Art und Weise, wie er in der Benutzeroberfläche angezeigt wird.Antworten:
Ja, Getter / Setter unterbrechen die Kapselung - sie sind im Grunde genommen nur eine zusätzliche Ebene zwischen dem direkten Zugriff auf das zugrunde liegende Feld. Sie können genauso gut direkt darauf zugreifen.
Wenn Sie nun komplexere Methoden für den Zugriff auf das Feld benötigen, ist dies gültig, aber anstatt das Feld verfügbar zu machen, müssen Sie sich überlegen, welche Methoden die Klasse stattdessen anbieten soll. dh Anstatt einer Bank-Klasse mit einem Money-Wert, der über eine Eigenschaft verfügbar gemacht wird, müssen Sie überlegen, welche Zugriffsarten ein Bank-Objekt bieten soll (Geld hinzufügen, abheben, Guthaben abrufen), und diese stattdessen implementieren. Eine Eigenschaft für die Money-Variable unterscheidet sich nur syntaktisch davon, die Money-Variable direkt verfügbar zu machen.
DrDobbs hat einen Artikel , der mehr sagt.
Für Ihr Problem hätte ich 2 Methoden setStyle und clearStyle (oder was auch immer), die eine Aufzählung der möglichen Stile nehmen. Eine switch-Anweisung innerhalb dieser Methoden würde dann die relevanten Werte auf die entsprechenden Klassenvariablen anwenden. Auf diese Weise können Sie die interne Darstellung der Stile in eine andere Form ändern, wenn Sie sie später als Zeichenfolge speichern (z. B. zur Verwendung in HTML). In diesem Fall müssten auch alle Benutzer Ihrer Klasse geändert werden Eigenschaften holen / setzen.
Sie können weiterhin Strings einschalten, wenn Sie beliebige Werte annehmen möchten, entweder eine große if-then-Anweisung (falls es einige davon gibt) oder eine Zuordnung von String-Werten zu Methodenzeigern mithilfe von std :: mem_fun (oder std :: function ) so wird "fett" in einem Zuordnungsschlüssel gespeichert, dessen Wert sts :: mem_fun für eine Methode ist, die die Variable fett auf true setzt (wenn die Zeichenfolgen mit den Namen der Mitgliedsvariablen identisch sind, können Sie auch verwenden das stringifizierende Makro , um die Menge an Code zu reduzieren, die Sie schreiben müssen)
quelle
styles.setStyle(BOLD, true)
? Ist das korrekt?styles.getStyle(BOLD)
wenn Sie nicht nur Mitgliedsvariablen vom Typ Boolean, sondern auch vom Typ Integer und String haben (zum Beispiel:)styles.getStyle(FONTSIZE)
. Wie programmieren Sie das, da Sie Rückgabetypen nicht überladen können? Ich weiß, Sie könnten leere Zeiger verwenden, aber das klingt für mich wirklich schlecht. Haben Sie Hinweise dazu?Eine Idee, die Sie möglicherweise nicht berücksichtigt haben, ist das Decorator-Muster . Anstatt Flags in einem Objekt zu setzen und diese Flags dann auf alles anzuwenden, was Sie schreiben, binden Sie die Klasse, die das Schreiben ausführt, in Decorators ein, wodurch die Stile angewendet werden.
Der aufrufende Code muss nicht wissen, wie viele dieser Wrapper Sie um Ihren Text gelegt haben, sondern ruft lediglich eine Methode für das äußere Objekt auf und ruft den Stapel auf.
Für ein Pseudocode-Beispiel:
Und so weiter, für jeden Dekorationsstil. In seiner einfachsten Verwendung kann man dann sagen
Und der Code, der diese Methode aufruft, muss nicht genau wissen, was er empfängt. Solange es ETWAS ist, das Text mit einer WriteString-Methode zeichnen kann.
quelle
TextWriter
mit beidenBoldDecorator
undItalicDecorator
(bidirektional) darüber sprechen , um die Aufgabe zu erledigen.Ich würde mich zur zweiten Lösung neigen. Es sieht eleganter und flexibler aus. Obwohl es schwierig ist, sich andere Typen als fett, kursiv und unterstrichen (überstrichen?) Vorzustellen, wäre es schwierig, neue Typen mithilfe von Elementvariablen hinzuzufügen.
Ich habe diesen Ansatz in einem meiner letzten Projekte verwendet. Ich habe eine Klasse, die mehrere boolesche Attribute haben kann. Die Anzahl und Namen der Attribute können sich mit der Zeit ändern. Ich speichere sie in einem Wörterbuch. Wenn ein Attribut nicht vorhanden ist, gehe ich davon aus, dass sein Wert "false" ist. Ich muss auch eine Liste der verfügbaren Attributnamen speichern, aber das ist eine andere Geschichte.
quelle
Ich denke, Sie überdenken das Thema.
styles.setBold(true)
undstyles.setItalic(false)
sind OKquelle