オブジェクト指向プログラミング:ゲッター/セッターまたは論理名


12

私は現在、書いているクラスへのインターフェースについて考えています。このクラスには、キャラクターのスタイル、たとえば、キャラクターが太字、斜体、下線などが含まれます。これらのスタイル。私は論理名を好む傾向がありますが、それは効率的でも論理的でもないコードを書くことを意味します。例を挙げましょう。

私はクラスの持っているCharacterStylesメンバ変数があるbolditalicunderline(およびいくつかの他の人を、私はそれをシンプルに保つためにそれらを残しておきます)。最も簡単な方法は、あなたが行うことができるように、書き込みgetter / setterメソッドになり、これらの変数にアクセスするには、プログラムの他の部分を可能にstyles.setBold(true)してstyles.setItalic(false)

しかし、私はこれが好きではありません。多くの人がゲッター/セッターがカプセル化を破ると言っているだけでなく(それは本当にそんなに悪いのですか?)私は、styles.format("bold", true)これらのすべての方法ではなく、1つの方法などでキャラクターのスタイルを設定することを期待しています。

ただし、1つの問題があります。C ++の文字列の内容ではオブジェクトメンバー変数にアクセスできないため、すべてのスタイルに対して大きなifステートメント/スイッチコンテナーを記述するか、スタイルを連想配列に格納する必要があります(地図)。

最善の方法がわからない。ある瞬間、私はゲッター/セッターを書くべきだと思い、次の瞬間、私は他の方法に傾く。私の質問は:あなたは何をしますか?そして、なぜあなたはそれをするのでしょうか?


CharacterStylesクラスは、実際には3つのブール値をバンドルする以外のことを行いますか?どのように消費されますか?
マークカンラス

はい、CharacterStylesは他のCharacterStylesから継承できる必要があるためです。つまり、にbold設定されたCharacterStylesがtrueあり、他の変数が未定義の場合、他の変数のgetterメソッドは親スタイル(別のプロパティに格納されている)の値を返し、プロパティのgetter boldはを返す必要がありますtrue。他にも、名前やインターフェースでの表示方法などがあります。
カエル

enumを使用してさまざまなスタイルオプションを定義し、switchステートメントを使用できます。ところで、未定義の処理方法は?
ティアナ

@Tyanna:実際、enumの使用についても考えましたが、それはほんの少しの詳細です。未定義の値をNULLに設定するだけでした。それが最善の方法ではありませんか?
カエル

回答:


6

はい、ゲッター/セッターはカプセル化を解除します-基本的には、基本フィールドに直接アクセスするための単なる追加レイヤーです。直接アクセスすることもできます。

ここで、フィールドにアクセスするためのより複雑なメソッドが必要な場合、それは有効ですが、フィールドを公開する代わりに、クラスが提供するメソッドを代わりに考える必要があります。すなわち。プロパティを使用して公開されるMoney値を持つBankクラスの代わりに、Bankオブジェクトが提供するアクセスの種類(お金の追加、引き出し、バランスの取得)を考え、代わりにそれらを実装する必要があります。Money変数のプロパティは、Money変数を直接公開する場合と構文的にのみ異なります。

DrDobbsにはさらに多くの記事があります。

あなたの問題のために、可能なスタイルの列挙型をとる2つのメソッドsetStyleとclearStyle(または何でも)があります。これらのメソッド内のswitchステートメントは、適切なクラス変数に関連する値を適用します。この方法では、後でHTMLで使用するために文字列として保存することにした場合、スタイルの内部表現を別のものに変更できます-使用した場合、クラスのすべてのユーザーも変更する必要があるものプロパティを取得/設定します。

任意の値を取得する場合、大きなif-thenステートメント(いくつかある場合)、またはstd :: mem_fun(またはstd ::を使用したメソッドポインターへの文字列値のマップ)のいずれかを使用する場合、ストリングをオンに切り替えることができますfunction)そのため、「bold」は、値がsts :: mem_funであるマップキーに格納され、変数boldをtrueに設定するメソッドになります(文字列がメンバー変数名と同じ場合は、書く必要があるコードの量を減らすための文字列化マクロ


素晴らしい答えです!特に、データをHTMLとして保存する部分は、実際にこの道を進む正当な理由として思い当たりました。したがって、さまざまなスタイルを列挙に保存してから、次のようなスタイルを設定することをお勧めしstyles.setStyle(BOLD, true)ますか?あれは正しいですか?
カエル

はい、setStyle(BOLD)とclearstyle(BOLD)の2つのメソッドしかありません。2番目のパラメータを忘れて、私はそのようにそれを好みます、そして、あなたはすべてのスタイルフラグをクリアするためにパラメータを取らないためにclearStyleをオーバーロードできます。
gbjbaanb

一部のタイプ(font-sizeなど)にはパラメーターが必要なため、これは機能しません。しかし、まだ答えてくれてありがとう!
カエル

私はこれを実装しようとしてきたが、私は考慮していない一つの問題があります:あなたはどのように実装するかstyles.getStyle(BOLD)、あなただけboolean型の、だけでなく、種類の整数と(例:文字列のメンバ変数を持っていないときはstyles.getStyle(FONTSIZE))。戻り値の型をオーバーロードできないため、これをどのようにプログラムしますか?voidポインターを使用できることは知っていますが、それは私にとって本当に悪い方法のように思えます。これを行う方法についてのヒントはありますか?
カエル

ユニオンまたは構造体を返すことができます。または、新しい標準では、戻り値の型でオーバーロードできます。そうは言っても、スタイルを設定する単一のメソッドを実装しようとしていますか?スタイルはフラグ、フォントファミリ、およびサイズです?この場合、抽象化を少し強引にしようとしているのかもしれません。
-gbjbaanb

11

あなたが考慮しなかったかもしれない一つのアイデアは、デコレータパターンです。オブジェクトにフラグを設定してから、作成しているものにそれらのフラグを適用するのではなく、デコレータで書き込みを行うクラスをラップして、スタイルを適用します。

呼び出し元のコードは、テキストを囲むラッパーの数を知る必要はありません。外側のオブジェクトのメソッドを呼び出すだけで、スタックを呼び出します。

擬似コードの例:

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のみです。


うーん、私はあしたを新鮮な心でその明日を見て、それからあなたに戻ります。答えてくれてありがとう。
カエル

私は、デコレータパターンの大ファンです。このパターンがHTMLに似ているという事実(コア操作は入力文字列をタグで囲むことです)は、このアプローチがインターフェイスユーザーのすべてのニーズを満たすことができるという証明です。心に留めておくべきことの1つは、優れた使いやすいインターフェースには、技術的に複雑な基礎となる実装が含まれている可能性があるということです。たとえば、実際にテキストレンダラーを実際に実装している場合、ジョブを完了するTextWriterには両方BoldDecoratorItalicDecorator(双方向で)話しかける必要があることがわかります。
-rwong

これはいい答えですが、opの質問を再紹介しませんか?「太字のアプリケーション」->これはどのように行われますか?SetBold()のようなセッター/ゲッターを使用していますか?これはまさにopの質問です。
stijn

1
@stijn:そうでもない。その状況を回避する方法はいくつかあります。たとえば、BuildDecoratedTextWriterを呼び出したときに最終アイテムを装飾するだけで、配列にデコレータを追加および削除するtoggleStyleメソッド(enum引数)でビルダーでラップできます。または、rwongが提案したように実行して、基本クラスを複雑にすることができます。状況に依存しますが、OPは全体的な仕様について十分に具体的ではなく、どちらが彼にとって最適かを推測できませんでした。彼はパターンを取得したら、それを理解できるほど頭がいいようです。
pdr

1
デコレータパターンは、装飾の順序を意味するものだといつも思っていました。示されているサンプルコードを検討してください。ItalicDecoratorを削除するにはどうすればよいですか?それでも、デコレーターのようなものが行く方法だと思います。太字、斜体、下線だけが3つのスタイルではありません。細い、半太字、凝縮、黒、幅広、斜体、斜体などがあります。キャラクターに任意の大きなスタイルセットを適用する方法が必要になる場合があります。
バリーブラウン

0

私は2番目の解決策に傾くでしょう。よりエレガントで柔軟に見えます。太字、斜体、下線(上線?)以外の型を想像することは困難ですが、メンバー変数を使用して新しい型を追加することは困難です。

私は最新のプロジェクトの1つでこのアプローチを使用しました。複数のブール属性を持つことができるクラスがあります。属性の数と名前は時間とともに変化する場合があります。辞書に保存します。属性が存在しない場合、その値は「false」であると想定します。利用可能な属性名のリストも保存する必要がありますが、それは別の話です。


1
これらのタイプとは別に、取り消し線、フォントサイズ、フォントファミリ、上付き文字、下付き文字などを後で追加します。しかし、なぜプロジェクトでその方法を選択したのですか?許可された属性のリストを保存する必要があるのは汚いコードだと思いませんか?これらの質問に対するあなたの答えが何であるか本当に興味があります!
カエル

アプリケーションが既にデプロイされているときに、クライアントがいくつかの属性を定義できる状況に対処する必要がありました。一部のクライアントには他の属性が必要でしたが、他の属性は廃止されました。フォーム、保存されたデータセットをカスタマイズし、このアプローチを使用して他の問題に対処できました。汚いコードを生成するとは思わない。顧客がどのような情報が必要になるかを予測できない場合があります。
アンジェイBobak

しかし、私の顧客はカスタム属性を追加する必要はありません。そしてその場合、私はそれが少し「ハック」に見えると思います。同意しませんか?
カエル

動的な数の属性の問題に直面しない場合、それらを格納するための柔軟なスペースは必要ありません。それは本当です:)しかし、私は他の部分に同意しません。辞書/ハッシュマップなどの属性を記憶することは、私の意見では悪いアプローチではありません。
アンジェイBobak

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.