web-dev-qa-db-ja.com

データクラス:ゲッターとセッターまたは異なるメソッド設計

私が書いているデータクラスのインターフェイスを設計しようとしています。このクラスは、文字のスタイル(たとえば、文字が太字、斜体、下線付きなど)を格納します。しかし、font-sizeとfont-familyも。したがって、さまざまなタイプのメンバー変数があります。これを実装する最も簡単な方法は、すべてのメンバー変数にゲッターとセッターを追加することですが、これは私には間違っていると感じています。 style.format(BOLD, true)の代わりにstyle.setBold(true)を呼び出す方が、より論理的(そしてOOP)に感じられます。したがって、ゲッター/セッターの代わりに論理メソッドを使用します。

しかし、これらのメソッドの実装中に2つの問題に直面しています。C++では文字列の内容で変数にアクセスできないため、すべてのメンバー変数を含む大きなswitchステートメントが必要になります。さらに、戻り値の型でオーバーロードすることはできません。つまり、style.getFormatting(BOLD)のような1つのゲッターを作成することはできません(これを行うには tricks があることは知っていますが、これらはありません) tは、私が明らかに必要とするであろうパラメータを考慮に入れます。

ただし、ゲッターとセッターを実装する場合にも問題があります。スタイルも親スタイルを持つことができるため、かなりのコードを複製する必要があります。つまり、ゲッターは、このスタイルのメンバー変数だけでなく、親スタイルの変数も調べる必要があります。

これを行う方法がわからなかったので、数週間前に質問することにしました。 オブジェクト指向プログラミング:ゲッター/セッターまたは論理名 を参照してください。しかし、その質問では、それは単なるデータオブジェクトであり、テキストレンダリングエンジンを作成していないことを強調しませんでした。そのため、回答した人の1人が、それを明確にしながら別の質問をするよう提案しました(彼の理由により)ソリューション、デコレータパターンは私の問題には適していません)。したがって、私は独自のテキストレンダリングエンジンを作成するのではなく、これらのクラスを使用してデータを格納していることに注意してください。

私はまだこの問題の解決策を見つけることができなかったので、もう一度この質問をしたいと思います。このようなスタイルクラスをどのように設計しますか?そして、なぜあなたはそれをしますか?

7
Frog

パート1

これは良い設計問題です。あなたはゲッターとセッターに関するコードのにおいを検出することにおいて正しいです。それらは通常、オブジェクトの実装の詳細を公開する設計上の問題を示します。

オブジェクトが何をすべきかについて考えてみてください-教えて、聞かないで:

最初の問題は、「データクラス」を設計しようとしていることです。データ(実装の詳細)を心配するのではなく、機能を考えてください。繰り返しますが、オブジェクトは何をすべきですか?あなたの場合、文字スタイルをどうしたいですか? (ソフトウェア的に)誰が文字スタイルを気にしますか?彼らは何をする必要がありますか?

うまくいけば、それであなたは始められます。テスト駆動開発は、この種の設計上の問題に役立ちます。データではなく機能の観点から考える必要があります。

逆に、必要なのがデータコンテナーだけの場合は、Cスタイルのstructクラスを記述して町に行きます。それを維持することは$ @#%#になることをお勧めしません。

幸運を!

パート2

必要なのは、単純なデータクラス-ゲッターとセッターを完全にスキップするか、ファサード(ファサードパターン)を前に配置するプラットフォーム非依存抽象化を作成するかのいずれかです。レンダリングとスタイル設定。スタイルの設定とレンダリングのためのインターフェースを提供するだけです。ご使用のプラットフォーム固有の実装がダーティな作業を行います(例ではNSTextViewを使用)。

単純なデータクラスの利点は、書き込みが最初は単純であるということです。その欠点は、if-elseステートメントの巨大なもつれを回避するのに苦労することです。 スタイルを使用するプラットフォーム固有レンダリング呼び出しを作成するための明確な場所も不足します。システムの複雑さが増すにつれて、実装の詳細をどこに置くかを決定することがより困難になる場合があります。

ファサードはより抽象化されたアプローチです。利点は、柔軟性が高く、別のプラットフォームに移植する場合に再利用できることです。その欠点は、先行開発期間が増えることです。

ファサードのパブリックインターフェースは、スタイルを設定および削除するために必要なものを提供し、時間になるとレンダリングを開始します。

スタイルの設定方法の詳細は自由です。これまでにシステムが最も感じているものを使用します。シンプルなgettersとsettersまたはジェネリックsetgetは、内部でディクショナリを使用します(使用している場合は、ブーストptreeを参照してください) C++)。構築時にすべての(またはデフォルトの)スタイルを取ることもできます。その時点ではミューテーターすら公開しないこともできます。あなたの電話。おそらく、サポートするスタイルをデータ駆動し、構成に加えて工場システムを使用することが重要であると判断した場合(それが重要であれば、後で詳細を追加できます)。実際、ファサードの実装方法が異なれば、問題へのアプローチ方法も異なります。いくつかのプロトタイプを作成して、最適なものを選択できます。

ファサード抽象化のプラットフォーム固有の実装では、プラットフォーム固有のレンダリングシステム(この場合はNSTextView)と、適切な呼び出しを行うために設定したスタイルを使用しますシステム。構築時にプラットフォーム固有のクラスを注入(依存性注入)し、render()メソッドを実装するだけでよいのです。

パート3

システム設計が許せば、構築時に特定の要素のすべてのスタイルを取ることができます。これにより、要素を不変にすることを選択した場合、ゲッターとセッターを完全に回避できます。そうすれば、キャラクタースタイルシステムの前に、シンプルでクリーンで不変の抽象化が可能になります。不変の状態では、一般にバグは少なくなりますが、物事を自由に変更できないという前提の下で操作する必要があります。

これをさらに一歩進めると、構成ファイルは、さまざまなスタイル設定を定義している可能性があります。繰り返しますが、これには、設定しているスタイルについての事前の知識が必要です(上記のスタイルを使用して構築する場合と同様)。探しているスタイルのタイプを指定します。たとえば、「見出し」とすると、より太字のフォントを指定する見出しの構成を取得できます。

これらは私の頭の上のアイデアのほんの一部です。それ以上の要件の収集と使用例がないと、より具体的に取得することは困難になります。

お役に立てば幸いです。幸運を!

9
hiwaylon

帰属リストの匂いがします。リストを使用する場合を除き、フォーマットを設定してフォーマットを取得する必要があることに同意します。属性で許可されている場合でもビットマスク。それ以外の場合は、可能な場合はIOCを使用してフィールドをフォーマットするフォーマッタオブジェクトの配列を保持してください。許してください。C++はわかりません。

Public abstract class IFormatter
{
.   public abstract void FormatText(TextField* fieldToFormat);
}

Public class BoldFormatter : IFormatter
{...}

Public class TextField
{
.   public void AddFormatter(IFormatter* formatterToAdd)
.   {...}

.   public IFormatter[] GetFormatters()
.   {...}

.   public void Render()
.   {
.       foreach(IFormatter formatter in formatters)
.       { formatter.FormatText(this); }
}
2
Jimmy Hoffa

データを保存するだけの場合は、なぜゲッターやセッターの種類を気にする必要があるのでしょうか。実施する不変条件、データを制御する論理的な理由、データを処理したりアクセスを妨げたりする理由はありません。クラスの理由は「データの保存」です。だからそれはいくつかのデータを格納し、それのままにしておきます。

2
DeadMG