設計に関する質問:使用するフィールドを渡すか、それともオブジェクトを渡すか?

StackOverflow https://stackoverflow.com/questions/1092628

  •  11-09-2019
  •  | 
  •  

質問

メソッド インターフェイスに関して 2 つの相反する戦略がよく見られますが、大まかにまとめると次のようになります。

// Form 1: Pass in an object.
double calculateTaxesOwed(TaxForm f) { ... }

// Form 2: Pass in the fields you'll use.
double calculateTaxesOwed(double taxRate, double income) { ... }

// use of form 1:
TaxForm f = ...
double payment = calculateTaxesOwed(f);

// use of form 2:
TaxForm f = ...
double payment = calculateTaxesOwed(f.getTaxRate(), f.getIncome());

特に、どのフィールドが使用されているかを評価するのが難しい動的言語では、2 番目の形式を支持する人たちを見てきました。

ただし、私は最初の形式の方が好きです。短くなり、エラーが発生する余地が少なくなります。また、後でオブジェクトの定義が変更された場合でも、必ずしもメソッド シグネチャを更新する必要はなく、おそらくメソッド内でのオブジェクトの操作方法を変更するだけで済みます。

どちらの形式についても、説得力のある一般的なケースはありますか?最初の形式ではなく 2 番目の形式を使用する必要がある場合についての明確な例はありますか?あるフォームを他のフォームよりも使用する決定を正当化するために指摘できる SOLID または他の OOP 原則はありますか?動的言語を使用している場合、上記の回答のいずれかが変わりますか?

役に立ちましたか?

解決

正直なところ、それは問題になっている方法によって異なります。

メソッドは、オブジェクトなしで理にかなっている場合は、

、第2の形態は、再利用することが容易であり、2つのクラスの間の結合を削除します。

メソッドは、オブジェクトに依存している場合は、公正に十分なオブジェクトを渡します。

おそらくあなたはその方法で動作するように設計されたインターフェースを通過し第三のフォームのために良いの引数があります。あなたの第二の柔軟性を持つ最初の形式の明瞭さを与えます。

他のヒント

それはメソッドの意図によって異なります。

メソッドが機能するように設計されている場合 特にそのオブジェクトに関して そのオブジェクトのみを渡します。それは素晴らしいカプセル化をもたらします。

しかし、その方法があれば、 より汎用的な, 、おそらくそうしたいでしょう パラメータを個別に渡す. 。こうすることで、情報が入ってきたときにメソッドが再利用される可能性が高くなります。 別の情報源から (すなわち、さまざまなタイプのオブジェクトまたはその他の派生データ)。

2 番目の解決策を強くお勧めします - calculateTaxesOwed() いくつかのデータを計算するため、数値入力が必要です。ビジネス ロジックをユーザー インターフェイスから分離する必要があるため、このメソッドはユーザー インターフェイスとはまったく関係がなく、入力としてフォームを使用するべきではありません。

計算を実行するメソッドは、(通常は) ユーザー インターフェイスと同じモジュールに属してはいけません。この場合、ユーザー インターフェイスにはビジネス ロジックが必要で、ビジネス ロジックにはユーザー インターフェイス フォームが必要であるため、循環依存関係が発生します。これは、何かが間違っていることを示す非常に強力な兆候です (ただし、インターフェイス ベースのプログラミングを使用すれば解決できる可能性があります)。

アップデート

納税フォームがユーザー インターフェイス フォームではない場合は、状況が少し変わります。この場合、インスタンス メソッドを使用して値を公開することをお勧めします。 GetOwedTaxes() またはインスタンスプロパティ OwedTaxesTaxForm クラスですが、静的メソッドは使用しません。計算を他の場所で再利用できる場合は、フォームではなく値を使用する静的ヘルパー メソッドを作成し、インスタンス メソッドまたはプロパティ内からこのヘルパー メソッドを呼び出すことができます。

私はそれが本当に重要とは思いません。あなたはそれが変異する可能性があるとして、あなたがオブジェクトを渡す場合は副作用に自分を開きます。しかし、これはあなたが望むかもしれません。これを緩和するために、(とテストを支援するために)あなたは、おそらくより良い具体的なタイプではなく、インタフェースを渡しています。利点は、あなたがオブジェクトの別のフィールドにアクセスしたい場合は、メソッドのシグネチャを変更する必要がないということです。

(あなたがインターフェイスを使用している場合、これは利益の少ないですが)

すべてのパラメータを渡すと、型が必要なもの、それが明確になり、それが簡単にテストすることになるかもしれません。しかし、あなたはより多くのリファクタリングを持つことになります。

そのメリットについて、それぞれの状況を判断し、最も苦痛を選びます。

引数だけを渡すと単体テストが簡単になる, なぜなら、本質的に単なる静的な計算である機能をテストするためだけに、データで満たされたオブジェクト全体をモックアップする必要がないからです。オブジェクトの多くのフィールドのうち、使用されているフィールドが 2 つだけの場合は、他のすべてが等しいとして、それらのフィールドだけを渡すことに傾きます。

そうは言っても、 最終的に 6 つ、7 つ以上のフィールドが必要になった場合は、オブジェクト全体またはフィールドのサブセットを「ペイロード」クラスに渡すことを検討してください。 (言語のスタイルに応じて、構造体/辞書)。長いメソッド シグネチャは通常、混乱を招きます。

もう 1 つのオプションは、何も渡す必要がないようにクラス メソッドにすることです。テストにはあまり便利ではありませんが、メソッドが TaxForm オブジェクトのデータに対してのみ使用される場合には検討する価値があります。

私は、これは、主に使用された例の人工物であることを認識し、それは多くの実世界の例には適用されないかもしれませんが、機能は、特定のクラスにそれほど強く結ばれている場合、それはすべきではありません。

double payment = f.calculateTaxesOwed;

税務上の文書は、関連する税金を計算するのではなく責任は特に異なる税のフォームは異なる税率表や計算方法を使用する傾向があることを考えると、ユーティリティ関数上に落下することを持つために責任自体を運ぶだろうと私には、より適切と思われます。

最初の形式の利点の 1 つは、

  1. 抽象化 - 実装ではなくインターフェイスに対するプログラミング。TaxForm のインターフェイスが変更されない限り、クライアント コードに影響を与えることなく TaxForm の実装を変更できるため、長期的にはコードのメンテナンスが容易になります。

これは、リファクタリングのMartin Fowler氏の著書から「パラメータの導入オブジェクト」と同じです。ファウラーは、一緒に渡される傾向にあるパラメータのグループがある場合は、このリファクタリングを行うことを示唆しています。

あなたがデメテルの法則を信じている場合は、あなたが必要とされているまさに渡し有利に働くます:

http://en.wikipedia.org/wiki/Law_of_Demeterする

http://www.c2.com/cgi/wiki?LawOfDemeterする

UIとデータの分離が操作する

あなたのケースでは、課税対象の実体を表す、たとえば、TaxInfoを中間クラスが欠落しています。その理由は、UI(フォーム)と(税率を計算する方法)は、ビジネスロジックは、2つの異なる「変更のトラック」、プレゼンテーション技術(「ウェブ」、「ウェブ2.0」、「WPF」、と1つの変化にあるということです。 ...)、法律用語でその他の変更。それらの間の明確なインタフェースを定義します。

<時間>

一般的な議論、例を使用して:

名刺用のビットマップを作成するための関数を考えてみましょう。関数の目的である

(1)の//姓と名から名刺のタイトルをフォーマットします。

または

(2)の//はPersonレコード

からbusinnesカードのタイトルをフォーマット

最初のオプションは、一般的にpreferrableある弱い結合と、より一般的です。ただし、変更要求に対してあまり堅牢多くの場合 - 例えば「ケース2017:名刺への初期の人物を追加」を検討してください。

(person.Initialを添加)の実装を変更する通常容易とのインターフェースを変更するよりも高速である。

の選択肢は、あなたが期待する変更の種類、最終的です:Personrecordからのより多くの情報が必要であること、それより可能性がある、またはあなたがPerson以外のデータ構造のためのビジネスカードのタイトルを作成することも可能性が高いです。

あなたは(1)または(2)私はむしろ(2)、のための構文清潔でいいと思うの目的のために、OPFすることはできませんanfdそれは、「未定」である場合。

私は、私はいつも秒1で行くだろう、2のいずれかを選択するよう指示された場合 - どのようなあなたは(何らかの理由で)支払うべき税金をcaculateする必要がありますが、あなたはTaxFormのインスタンスを持っていけないことを発見した場合?

これはかなり簡単な例である、しかし私は、比較的単純なタスクを行う方法は、それがされている必要がありますよりも使い方法ははるかに困難に、作成することが困難であった複雑な入力を持っていた例を見てきました。 (著者は、単に他の人がそのメソッドを使用する場合がありますことを考えられていなかった!)

個人的には、コードを読みやすくするために、私はprobbalyの両方を持つことになります:

double calculateTaxesOwed(TaxForm f) 
{
    return calculateTaxesOwed(f.getTaxRate(), f.getIncome());
}

double calculateTaxesOwed(double taxRate, double income) { ... }

親指の私のルールは、それが必要とする正確に入力を受け取るメソッドを持っている可能な限りにある - 。そのラッパー・メソッドを記述することは非常に簡単。

それははるかに明確にそれは方法が必要だということです何のだから

個人的に、私は#2に行きます。 TaxFormを渡す種類の臭いであると私は少しうんざりします(> _ <)(それは私がWindowsフォームのように、それが何を考えている場合)。

私のような最初に、あなたが他の方法では、最終的な結果を計算するために必要なものは何でもIncomeTaxCalculationInfoのTaxRateが含まれていますオブジェクトと所得と同様に、計算にDTO特定を渡している場合にのみ変化、決して何かを使用したいですWindowsの/ Webフォームます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top