12

メソッドインターフェイスの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の原則はありますか?動的言語を使用している場合、上記の回答のいずれかが変わりますか?

4

12 に答える 12

6

正直なところ、それは問題の方法に依存します。

メソッドがオブジェクトなしで意味をなす場合、2番目の形式は再利用が容易であり、2つのクラス間の結合を削除します。

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

そのメソッドで動作するように設計されたインターフェースを渡す3番目のフォームにはおそらく良い議論があります。最初のフォームの明瞭さと2番目のフォームの柔軟性を提供します。

于 2009-07-07T14:30:49.643 に答える
3

それはあなたの方法の意図に依存します。

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

ただし、メソッドがより汎用的な場合は、パラメーターを個別に渡すことをお勧めします。そうすれば、情報が別のソース(つまり、異なるタイプのオブジェクトまたは他の派生データ)からのものである場合に、メソッドが再利用される可能性が高くなります。

于 2009-07-07T14:27:11.787 に答える
2

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

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

アップデート

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

于 2009-07-07T14:30:45.183 に答える
1

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

すべてのパラメーターを渡すと、タイプに必要なものが明確になり、テストが容易になる可能性があります(ただし、インターフェースを使用する場合、これはあまりメリットがありません)。ただし、リファクタリングはさらに多くなります。

それぞれの状況をそのメリットで判断し、最も痛みの少ないものを選びます。

于 2009-07-07T14:27:36.873 に答える
1

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

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

The other option is to make it a class method, so you don't have to pass anything. It's less convenient to test, but worth considering when your method is only ever used on a TaxForm object's data.

于 2009-07-07T14:30:51.593 に答える
1

これは主に使用された例のアーティファクトであるため、多くの実際のケースには当てはまらない可能性があることを認識していますが、関数が特定のクラスに非常に強く結び付けられている場合は、そうすべきではありません:

double payment = f.calculateTaxesOwed;

私には、関連する税金を計算する責任を効用関数に委ねるよりも、税務書類自体がその責任を負う方が適切であると思われます。特に、異なる税形態は異なる税表または計算方法を使用する傾向があることを考えると.

于 2009-07-07T15:02:52.273 に答える
0

デメテルの法則を信じるなら、必要なものを正確に渡すことを好むでしょう:

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

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

于 2009-07-07T14:34:06.957 に答える
0

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

  1. 抽象化-実装ではなくインターフェースへのプログラミング。TaxFormのインターフェイスが変更されない限り、クライアントコードに影響を与えることなく、TaxFormの実装を変更できるため、長期的にはコードの保守が容易になります。
于 2009-07-07T14:28:24.000 に答える
0

これは、MartinFowlerのリファクタリングに関する本の「IntroduceParameterObject」と同じです。Fowlerは、一緒に渡される傾向のあるパラメーターのグループがある場合は、このリファクタリングを実行することをお勧めします。

于 2009-07-07T14:31:06.227 に答える
0

2つのうちの1つを選択させられた場合、常に2番目のものを使用します-(何らかの理由で)支払うべき税金を計算する必要があるが、のインスタンスがない場合はどうなりTaxFormますか?

これはかなり些細な例ですが、比較的単純なタスクを実行するメソッドに、作成が困難な複雑な入力があり、メソッドの使用が本来よりもはるかに困難になるケースを見てきました。(著者は、他の人がその方法を使いたがるかもしれないとは考えていませんでした!)

個人的には、コードを読みやすくするために、おそらく次の両方を使用します。

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

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

私の経験則は、可能な限り、必要な入力を正確に受け取るメソッドを用意することです。ラッパーメソッドを作成するのは非常に簡単です。

于 2009-07-07T16:21:00.943 に答える
0

個人的には、メソッドが必要とするものがより明確であるため、#2 を使用します。TaxForm を渡すのは (Windows フォームのように、私の考えでは) 臭くて、少しうんざりします (>_<)。

TaxRateとIncomeを含むIncomeTaxCalculationInfoオブジェクトなど、計算に固有のDTOを渡す場合にのみ、最初のバリエーションを使用しますが、メソッドで最終結果を計算するために必要なものは何でも使用しますが、Windows / Webのようなものは使用しません形。

于 2009-07-07T16:30:38.990 に答える
0

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

あなたの場合、課税対象のエンティティを表す中間クラス、たとえば TaxInfo がありません。その理由は、UI (フォーム) とビジネス ロジック (税率の計算方法) が 2 つの異なる「変更トラック」にあるためです。一方はプレゼンテーション テクノロジ (「Web」、「Web 2.0」、「WPF」など) によって変更されます。 ..)、その他は法律用語で変わります。それらの間の明確なインターフェースを定義します。


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

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

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

また

(2) //レコードから名刺のタイトルをフォーマットしますPerson

最初のオプションはより一般的で、結合が弱く、一般的に好ましい方法です。ただし、多くの場合、変更要求に対する堅牢性は低くなります。たとえば、「ケース 2017: 人物のイニシャルを名刺に追加する」を検討してください。

通常、実装を変更する (person.Initial を追加する) 方が、インターフェイスを変更するよりも簡単で高速です。

最終的には、どのような種類の変更を期待するかを選択します。レコードからより多くの情報Personが必要になる可能性が高いですか、それとも、他のデータ構造の名刺タイトルを作成する可能性が高いPersonですか?

それが「未定」の場合、(1) または (2) の目的で opf を実行することはできません。構文をきれいにするために、(2) を使用したいと思います。

于 2009-07-07T14:41:29.580 に答える