3

次の2つの方法があるとします。

番号1:

void AddPerson(Person person)
{
  // Validate person
  if(person.Name != null && IsValidDate(person.BirthDate)
    DB.AddPersonToDatabase(person);
}

2番:

void AddPerson(string name, DateTime birthDate)
{
  Person p = new Person(name, birthDate);
  DB.AddPersonToDatabase(person);
}

2つの方法のどちらが最適ですか?最初のものがOOに関してより正しいことは知っていますが、2番目のものの方が読みやすいと思います。パラメーターがこれを確認するので、オブジェクトが有効であることを確認する必要はありません。オブジェクトをパラメータとして渡す場所でオブジェクトを検証する必要はありません。他のアプローチはありますか?

編集:すべての答えのためのThx。明確にするために、コンストラクターとIsValidメソッドで検証することはもちろん良いアプローチですが、私のコードでは、人の有効な状態はコンテキストに依存することが多く、メソッドごとに異なる可能性があります。もちろん、これは悪い設計の兆候である可能性があります。

このコードは、問題を説明するための単なる例です。

4

12 に答える 12

10

最初の人はperson.Nameとperson.BirthDateを検証する必要はありません-これらはPersonコンストラクターによって自動的に検証される必要があります。言い換えれば、あなたが人を渡された場合、あなたはそれが有効であることを知っている必要があります。

一方、それがpersonnull参照ではないことを確認する必要があります。

ただし、コンストラクターを明示的に呼び出す必要がないように、2番目のバージョンのような便利なメソッドを使用する価値がある場合があります。通常は、Personコンストラクターを呼び出してから、作業を最初のフォームに委任する必要があります。

于 2008-12-31T14:28:41.993 に答える
2

1つ目は、既存のコードを壊さずにPerson定義を変更できるという利点があり、再コンパイルのみが必要です。2番目のものの方が読みやすいと思うかもしれませんが、最初のものの方が保守しやすく、選択できます。

于 2008-12-31T14:27:38.097 に答える
2

別のオプションは次のとおりです。

void AddPerson(Person person)
{  // Validate person  
   if(person.IsValid)
   {
     DB.AddPersonToDatabase(person);
   }
}

Personは、構築時に自分自身を検証しないと仮定します。オブジェクトが一時的なときに無効な状態になる可能性がある場合は、これが実行可能である場合があります。

于 2008-12-31T14:31:23.563 に答える
1

APIとオブジェクトの結合を減らすため、前者(オブジェクトを渡す)の方が好きです。オブジェクトを変更するPerson場合、たとえば、以前は必要なかったような新しいプロパティを追加するNickname場合、最初のケースではパブリックAPIを変更する必要はありませんが、2番目のケースではメソッドを変更するか追加する必要があります新しいオーバーロード。

于 2008-12-31T14:28:42.977 に答える
1

私はそれが完全に文脈に依存することに同意します、これのための絶対的な規則はありません。私の意見では、次のようなメソッドを使用するのは意味がありません。

person.SetBirthDate(Person person)
person.ResetPassword(Person person)

しかし、この場合、私は前者を好みます。なぜなら、Greg Beechが言ったように、メソッドはドメインオブジェクトについて何も知らない(する必要がある)からです。

ちなみに、オーバーロードを検討してください(DRY-Do n't Repeat Yourself):

void AddPerson(Person person)
{
  if(person.Name != null && IsValidDate(person.BirthDate)
    DB.AddPersonToDatabase(person);
}

void AddPerson(string name, DateTime birthDate)
{
  Person p = new Person(name, birthDate);
  this.AddPerson(p);
}
于 2008-12-31T14:35:41.933 に答える
1

一連のプリミティブ型をパラメーターとして渡すよりも、Personオブジェクトを渡す方が間違いなく優れています。次の2つの方法を比較します


public static void Withdrawal(Account account, decimal amount)
{
    DB.UpdateBalance(account.AccountNumber, amount);
}

public static void Withdraw(int accountNumber, decimal amount)
{
    DB.UpdateBalance(accountNumber, amount);
}

2つの方法はほぼ同じように見えますが、2番目の方法は安全ではありません。intはどこからでも取得できるので、次のように書くと困惑します。

private void CloseTransaction(Transaction tran)
{{
    BankAccounts.Withdrawal(tran.Account.RoutingNumber、tran.Amount);
        //論理エラー:Account.RoutingNumberの代わりにAccount.AccountNumberを渡すことを意味します
}

これは、コンパイルエラーや実行時例外をスローしないため、最悪の種類のエラーです。自動テストを十分に記述すれば、このエラーをキャッチする可能性がありますが、このバグは見逃しやすく、発見されることなく何ヶ月も隠れることができる可能性があります。

私は銀行のソフトウェアを書いている会社で働いていましたが、本番環境でこのタイプのバグに実際に遭遇しました。これは特定の種類のボールト転送中にのみ発生し、銀行の1つが月末のプロセスを実行するたびにGL残高が数ドルずれていることに気付いたときにのみ発見されました。銀行は何ヶ月もの間従業員の盗難を疑っていましたが、誰かが問題をソフトウェアのバグに突き止めたのは、慎重なコードレビューによってのみでした。

于 2008-12-31T15:50:29.363 に答える
0

私はほとんどの場合、最初のものに行きます。

2つ目は、Personの変更ごとに署名を壊します

于 2008-12-31T14:29:00.950 に答える
0

それは文脈に依存します。

すべての呼び出しメソッドがPersonオブジェクトを処理する場合、最初のメソッドが正しい解決策です。

ただし、呼び出しメソッドの一部が名前と生年月日を処理し、一部がPersonオブジェクトを処理する場合、2番目の例が正しい解決策です。

于 2008-12-31T14:29:23.133 に答える
0

両方にオーバーロードを作成します。特に自動的に作成できることを考えると。

于 2008-12-31T14:30:30.290 に答える
0

メソッドはPerson型の一部ではないと思います。Personそのことを念頭に置いて、私は両方とも別のタイプ( )imoについて少し知識が多すぎると感じています。最初のバージョンでは、有効な人物インスタンスの作成を検証する必要はありません。これが発信者の責任である場合、すべての発信者はこれを行う必要があります。それはもろいです。

2番目のバージョンは、このタイプのインスタンスを作成するため、別のタイプに強く依存しています。

私は間違いなく最初のバージョンを好みますが、検証部分をコードのその部分から移動します。

于 2008-12-31T14:37:02.117 に答える
0

オブジェクトを使用するとカプセル化が向上します。それが彼らの目的です。プリミティブを使いすぎると人は困ると思います。

無効な人物を作成することはできません。コンストラクターは有効なパラメーターをチェックし、無効な場合は IllegalArgumentException をスローするか、アサートに失敗する必要があります。これが契約によるプログラミングのすべてです。

于 2008-12-31T15:05:50.720 に答える
0

ジョンはかなりそれを釘付けにしたと思います。Person有効な Person がそのコンストラクターで作成されるようにする責任があります。

オブジェクトを作成するか作成しないPersonか (AddPerson メソッドまたはその呼び出し元)の責任については、以下を参照してください。

http://en.wikipedia.org/wiki/GRASP_%28Object_Oriented_Design%29#Creator

OOP における責任の問題についてです。あなたの特定のケースでは、AddPerson が DB インターフェイスへの呼び出しをラップしている場合、私はそれについてよくわかりません。その Person オブジェクトがそのコンテキスト外で何に使用されるかによって異なります。データベースに追加するデータを格納することのみを目的としている場合は、クラスのユーザーが Person クラスについて知る必要がなくなるため、AddPerson メソッドで作成することをお勧めします。.

于 2008-12-31T14:40:44.590 に答える