メソッドのパラメーターリストにオブジェクトまたはオブジェクト識別子を含める必要がありますか?


10

私たちのチームは次の議論をしています:

次の2つのメソッドがあるとします。

public Response Withdraw(int clubId, int terminalId,int cardId, string invoice, decimal amount);

public Response Withdraw(Club club, Terminal terminal,Card card, string invoice, decimal amount);

送信されたものは単なるIDです。

片方は、最初の方法が正しいと言います。ターミナルとクラブのIDしかないので、他に何もないことは明らかです。これが私のアプローチです。

反対側は、2番目の方法の方が柔軟性があるため、正しいと言います。

私たちはオブジェクトパラメータのアイデアに精通していますが、反対側もオブジェクトパラメータはオブジェクトをプロパティとして持つべきだと考えています。

正しいアプローチはどれですか?

たぶん3番目のさらに良いアプローチがありますか?


何?...........
ジェームズ

1
環境?ウェブサービス?WCF?
CodesInChaos 2013

1
@ジェームズ-申し訳ありませんが、この質問を少し早く書いたのですが、理解できないことを教えていただければ編集できますか?
ミシール2013

@CodesInChaosメソッドは実際にはBLメソッドです
Mithir

回答:


10

答えはコンテキストに依存します。

クライアントがそれらすべてのオブジェクトをすでに使用できると予想される場合は、オブジェクトパラメータを使用します。そうしないと、コードは必要以上に複雑に見えます。(例えば、彼らはのような呼び出しを持つでしょうclub.getId()。)

クライアントが簡単に利用できるIDしか持っていない場合は、実際にIDだけが必要な場合にクライアントがそれらすべてのオブジェクトをアセンブル/ロードする必要がない場合があるため、おそらく2番目のアプローチの方が適しています。

オプションは、両方のメソッドを提供することです。これにより、クライアントはどちらを使用するかを選択できます(これによりAPIが乱雑にならない場合)

一般に、オブジェクトパラメータはより拡張可能です。将来的に作業を行うために別のデータが必要になった場合、その追加情報を取得する別のメソッドを導入する必要がないためです。

最後に、メソッドのシグネチャは、メソッドが何をするか(あなたの場合、正確にはネットワークを介して行われること)の詳細によって指示されるべきではありません。APIは抽象的に意味をなす必要があるため、実装が変更されても、混乱することはありません。


3
+1もう1つだけポイントを追加します。リモートで呼び出されるメソッド( "over the Wire"?)の場合、オブジェクトを渡すと、広範なオブジェクトツリーを深くシリアル化する必要があります。IDは、リモート呼び出しペイロードのサイズが心配な場合に、オブジェクトの優れた代替品です。
ロスパターソン

1
この場合、一連の抽象化に結合しているように見えるため、Idを渡すことで柔軟性が高まることはなく、おそらくパラメーターを逆にする可能性が高くなります。問題は、メソッドのコードと、渡した抽象化がどの程度緊密であるかです。たとえば、「validateCreditCard(string card、string cvi)」のようなメソッドは、何らかの種類のCreditCardオブジェクトと密結合することを避けるために、おそらくプリミティブにとどまる必要があります。
ipaul 2013

途中で会って、パラメーターリストのインターフェイスを使用します。そうすれば、クラブはクラブになることができますが、将来的にはサウナになることもあります。
ピーターB

13

最初のアプローチは、原始的な強迫観念を示しています。intとstringを渡すため、プログラマーが間違いを犯しやすい(たとえば、clubIdをterminalIdパラメーターに渡す)のは非常に簡単です。これはバグを見つけるのを難しくします。

2番目の例では、ターミナルが予想されるときにクラブを渡すことは不可能です。これはコンパイル時のエラーになります。

それでも、私はまだ見ますstring invoice。請求書は本当に文字列ですか?どういうamount意味ですか?これはおそらく通貨価値です。

「ネットワーク経由で送信されるものは単なるIDです」という質問で述べました。これは正しいですが、この要件によってドメインが不明瞭にならないようにしてください。

このアプローチを支持して私が見た最も良い説明は、Object Calisthenicsのルール3でした:

int自体は単なるスカラーであるため、意味がありません。メソッドがintをパラメーターとして取る場合、メソッド名はインテントを表現するすべての作業を行う必要があります。同じメソッドがHourをパラメーターとして取る場合、何が起こっているかを確認する方がはるかに簡単です。このような小さなオブジェクトは、Hourパラメーターを受け取るメソッドにYearを渡すことができないため、プログラムをより保守しやすくすることができます。プリミティブ変数を使用すると、コンパイラーは意味的に正しいプログラムを作成するのに役立ちません。オブジェクトを使用すると、たとえ小さなオブジェクトであっても、コンパイラとプログラマの両方に、値とは何か、なぜ使用されているのかについての追加情報が提供されます。


では、2番目のアプローチが優先されますか?idプロパティだけが入力されたclubオブジェクトがある場合でも、
ミシール

これはランダムなブログのようです。何が好ましいかを示す証拠はありません。誰が何を優先するかを本当に気にしますか?あなたに合ったことをしてください
James

@ジェームスこの質問に対する明確な答えはありません。特に、OPがあまりコンテキストを提供していないためです。あるアプローチが他のアプローチよりも好ましいと断固として主張する人は誰でも、OPを不幸にしています。それは白黒ではありません。
MattDavey 2013

1
@James最初のアプローチでは、見つけにくいバグを導入することが非常に簡単になることを指摘しただけです。プリミティブ型が悪いと言っているのではありませんが、プリミティブ型の目的は、意味のあるドメイン型を構築することです。このコンテキストの外でそれらを使用することは、原始的な強迫観念コードの匂いのまさに定義です。
MattDavey 2013

5
@ジェームズ:MattDaveyの発言は、定評のある事実です。彼はネイティブ型が悪いと言っているのではなく、これを言っています:someMethod(int、int、int、int、string、decimal)は、someMethod(Club、Terminal、Card、Stringよりもクライアントが理解して使用するのがはるかに難しい) 、10進数)
c_maker

2

これには正解はありません。どちらのオプションもジョブに適している可能性があります。ほぼすべての方法で、請求書が私の額に溝を生みました。コードを読んだことから何がわかるのかわかりません。

IDを送信する場合は、両方のシステムをそれが表すものと密接に結合する必要があります。ClubIDは、clubsテーブルのキーです。さらに言えば、呼び出し元と呼び出し先の両方が、Clubsテーブルの呼び出し内容とそのデータベースを合意する必要があります。制約を課したくない、または課せない場合は、一般的な説明を使用してオブジェクトを渡します。ネイティブ、シリアル化、xml、名前=値は何でも、iniファイル:)

あなたが特定したように、それはあなたが「ネットワーク経由で」あなたを犠牲にするでしょう。識別子を送信するだけでそれを回避すると、別の場所でコストがかかります。だから、あなたに最も害を与えないのは、今(または後である可能性があります...)は、善対悪の指標です。

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