現在、作成中のクラスへのインターフェースについて考えています。このクラスには、文字が太字、斜体、下線などの文字のスタイルが含まれています。値を次のように変更するメソッドにゲッター/セッターまたは論理名を使用する必要があるかどうか、私は2日間自分自身と議論してきましたこれらのスタイル。私は論理名を好む傾向がありますが、それは効率的で論理的ではないコードを書くことを意味します。例を挙げましょう。
メンバー変数CharacterStyles
、bold
、italic
(および他のいくつかのクラスがありますが、保持するためにそれらを除外します)を持つクラスunderline
を持っていますそれは簡単です)。プログラムの他の部分がこれらの変数にアクセスできるようにする最も簡単な方法は、getter/setterメソッドを記述して、styles.setBold(true)
およびstyles.setItalic(false)
を実行できるようにすることです。
しかし、私はこれが好きではありません。多くの人がゲッター/セッターがカプセル化を壊すと言っているだけでなく(本当にそれが悪いのでしょうか?)、それは主に私には論理的に思えないためです。 styles.format("bold", true)
などの1つのメソッドで文字のスタイルを設定することを期待していますが、これらのすべてのメソッドではありません。
ただし、問題が1つあります。 C++では文字列の内容でオブジェクトメンバー変数にアクセスできないので、すべてのスタイルに対して大きなifステートメント/スイッチコンテナーを作成するか、スタイルを連想配列に格納する必要があります(地図)。
最善の方法がわからない。ある瞬間、私はゲッター/セッターを書くべきだと思い、次の瞬間は別の方法に傾けます。私の質問は:あなたは何をしますか?そして、なぜあなたはそれをしますか?
はい、ゲッター/セッターはカプセル化を壊します-それらは基本的に、基礎となるフィールドに直接アクセスする間の単なる追加レイヤーです。直接アクセスすることもできます。
ここで、フィールドにアクセスするためのより複雑なメソッドが必要な場合は有効ですが、フィールドを公開するのではなく、クラスが提供するメソッドを検討する必要があります。すなわち。プロパティを使用して公開されるMoney値を持つBankクラスの代わりに、Bankオブジェクトが提供するアクセスの種類(お金の追加、引き出し、残高の取得)を検討し、代わりにそれらを実装する必要があります。 Money変数のプロパティは、Money変数を直接公開することと構文的に異なるだけです。
DrDobbsには 記事 があり、さらに詳しく説明しています。
あなたの問題については、可能なスタイルの列挙型を取る2つのメソッドsetStyleとclearStyle(または何でも)があります。これらのメソッド内のswitchステートメントは、関連する値を適切なクラス変数に適用します。このようにして、後でスタイルとして(たとえば、HTMLで使用するために)文字列として格納することにした場合、スタイルの内部表現を別のものに変更できます。これは、すべてのユーザーにを必要とするものです。 get/setプロパティを使用した場合も、変更するクラス。
任意の値を取得したい場合は、文字列をオンに切り替えることができます。大きなif-thenステートメント(それらがいくつかある場合)、または stdを使用して文字列値をメソッドポインターにマップします。 :mem_fun (または std :: function )したがって、「ボールド」は、その値がsts :: mem_funであるメソッドへのマップキーに格納されます。変数の太字をtrueに設定します(文字列がメンバー変数名と同じである場合、 stringifyingマクロ を使用して、記述する必要があるコードの量を減らすこともできます)
あなたが考慮しなかったかもしれない1つのアイデアは、 デコレータパターン です。オブジェクトにフラグを設定してから、これらのフラグを書き込み内容に適用するのではなく、書き込みを行うクラスをデコレーターでラップし、スタイルを適用します。
呼び出し側のコードは、テキストを囲むこれらのラッパーの数を知る必要はありません。外側のオブジェクトのメソッドを呼び出すだけで、スタックを呼び出します。
擬似コードの例:
class TextWriter : TextDrawingInterface {
public:
void WriteString(string x) {
// write some text somewhere somehow
}
}
class BoldDecorator : TextDrawingInterface {
public:
void WriteString(string x) {
// bold application on
m_textWriter.WriteString(x);
// bold application off
}
ctor (TextDrawingInterface textWriter) {
m_textWriter = textWriter;
}
private:
TextWriter m_TextWriter;
}
など、装飾スタイルごとに。最も簡単な使用法では、次のように言うことができます
TextDrawingInterface GetDecoratedTextWriter() {
return new BoldDecorator(new ItalicDecorator(new TextWriter()));
}
そして、このメソッドを呼び出すコードは、受信しているものの詳細を知る必要はありません。 WriteStringメソッドを介してテキストを描画できるのがSOMETHINGである限り。
私は2番目の解決策に傾倒します。よりエレガントで柔軟に見えます。太字、斜体、下線(上線?)以外の型を想像するのは難しいですが、メンバー変数を使用して新しい型を追加するのは難しいでしょう。
私は最新のプロジェクトの1つでこのアプローチを使用しました。複数のブール属性を持つことができるクラスがあります。属性の数と名前は、時間の経過とともに変化する可能性があります。辞書に保存しています。属性が存在しない場合、その値は「false」であると想定します。使用可能な属性名のリストも保存する必要がありますが、それは別の話です。
あなたは問題を考えすぎていると思います。
styles.setBold(true)
およびstyles.setItalic(false)
は問題ありません