web-dev-qa-db-ja.com

パラメータが関連するメソッドのコンストラクタにパラメータを渡す必要があるかどうかをどのように決定しますか?

私はPythonを使用していますが、私の質問は一般的にOOPに当てはまります。クラスを作成するときはいつでも、パラメータ/属性をコンストラクタ、またはパラメータが関連するメソッド。

たとえば、days_awayメソッドを持つPersonクラスを考えてみましょう。 days_awayの役割は、いくらtimestampsを与えられた人がdays離れているかを計算することです。 Personのコンストラクター(つまり、__init__)は、パラメーターとしてnameを取得します。また、パラメータとしてtimestampsを取得しますか、またはtimestampsは、特定の日時の期間で人が何日間離れていたかを計算することになっているdays_awayメソッドのパラメータとして取得しますか?どうして?

編集:コンテキストを追加します。これはアパートを共有する人の間で電気代を分けるためです。請求書は、人がその日を支払う必要がないように、人がいなくなった日数の関数として分割されます。離れた日数は、その人が残してアパートに戻ったときのタイムスタンプを指定して、days_awayメソッドによって計算されます。

9
Andy Gondzer

使用しているコードを見ます。

これの違いは何ですか

duration = Person(then).days_away(now)

この?

duration = Person().days_away(then, now)

何も。だが

duration = person.days_away(now)

違います。このコードはthenを知っている必要はありません。 nowを知っていれば十分です。それは非常に強力です。このコードは、nowのみを知っている場所で機能します。

したがって、唯一の問題は、thennowから分離する必要があるかどうかです。そうでない場合は、まあ。

9
candied_orange

インスタンスメンバーを使用するかどうかを理解する1つの方法。コンストラクターのパラメーターとして渡されるか、メソッドのパラメーター、またはその他は、情報の存続期間を考慮することです。

Persontimestampsがあり、実質的に人物オブジェクトと同じ長さで存続する場合、それはおそらくそれが属している場所です。

ある見方をすれば、オブジェクトは、情報を抽象化するための情報の結合です。このバインディングは、オブジェクトの持続時間に適していると思います。このバインディングは、コンストラクターパラメーターを介して行われます(理想的には、それができない場合があります)。

ただし、インスタンスフィールドを使用してパラメーターをメソッドに渡すことは望ましくありません。パラメーターとしてグローバル変数を使用する場合と同じ問題が多く発生します(たとえば、扱いにくくエラーが発生しやすく、スレッドセーフではありません)。

personが異なるさまざまな状況で、同じtimestampsdays_awayメソッドを呼び出すことはできますか?その場合、timestampsperson自体よりも有効期間が短い(少なくともライフタイムは間違いなく異なる)ため、コンストラクターパラメーターではなくメソッドパラメーターとして属します。

要約すると、何かを1つの抽象にバインドしますか、または1つのアイテムを動的に提供するつもりですか?セットおよびリセットし、バインディングで得られる範囲を超える状況で使用されます。

6
Erik Eidt

それは依存関係、範囲、思考プロセスについてです。後者から始めましょう。

あなたはたぶんあなたがそれを機能させる方法をあなた自身に尋ねるこの種の問題について行くでしょう。作成しようとしているオブジェクトのアプリケーションをすでに考えており、そのタスクに焦点を当てています。 OO進むべき道ではありません。シナリオベースのソリューションにジャンプしています。

Personクラスが必要だと認識したら、それに焦点を当てて、個人を識別するのは何かと考えます。それを人と呼ぶ前に、あなたはそれについて何かを知る必要がありますか? personオブジェクトはいつアプリケーションで意味を持ち始めますか?

名前の場合は、コンストラクターが取得します。それが人々が数である政府のアプリケーションのためであるならば、あなたは人を全体にするためにその数が必要になります。それが配達サービスの場合は、結局のところ、そのアドレスにもっと興味があり、その人自身がそのアドレスの知っているだけの属性であることに気づくかもしれません。

上記は、何かのタスクで後で必要になる可能性があるという理由だけで、オブジェクトコンストラクターにデータを注入できないようにする必要があります。コンストラクターのタスクは、オブジェクトを作成することであり、動作を準備することではありません。

今あなたの例です。 DaysAwayは行為ではなく、メソッドであってはなりません。どうやらあなたは欠席に対処する必要があります。それがすべてである場合、プロパティとしてPersonにタイムスロットのリストを含め、その人物が別の期間不在になることがわかったときにスロットを追加できますが、予定表オブジェクトプロパティを使用するほうがよい場合があります。ですから良い例ではないと思います。

データがオブジェクトに関連付けられているのではなく、行為に関連付けられている場合は、パラメーターとしてメソッドに渡す必要があります。オブジェクトは、あるコンテキストのあるタスクのある時点で必要となる可能性のある変数のコートラックではありません。オブジェクトデータは、オブジェクトの存続期間中、オブジェクト自体にとって意味のあるものでなければなりません。これは、スコープと依存関係の問題の両方をカバーしています。

4
Martin Maat

クラスに属するデータは、コンストラクターに入れる必要があります。このデータは、プライベートフィールドに配置してカプセル化するのが理想的です。メソッドはこのデータを操作できますが、クラスに属さない追加のデータがメソッドで必要になる場合があります。

人が私的なフィールドとして生年月日を持ち、特定の日付での人の年齢を知りたいとします。その2番目の日付は、年齢を計算するメソッドの引数でなければなりません。

3
Rik D

コンストラクターを考える1つの方法は、「完全」であることが必要なものでオブジェクトインスタンスをインスタンス化する関数です。

Bagのオブジェクトが必要で、Bagを空にできる場合、そのコンストラクターまたはそのコンストラクターを作成して、変数を渡す必要がないようにすることができます。

Bag b = new Bag();

ただし、オブジェクトがおそらくデータベース接続の場合、この不自然な図では、オブジェクトがデータベースに接続するために「必須」であるため、コンストラクターにはdataBasePasswordやdatabaseUserNameなどの属性が必要になる可能性があります。

DatabaseConnection dc = new DatabaseConnection(user, pwd);
2
mrflash818

次のヒューリスティックがほとんどの場合に非常に役立つことがわかりました。

前提

  • オブジェクトをインスタンス化する場所と、オブジェクトを呼び出す場所の両方がで区切られていますtime、およびscope内。

定理

  • injectionのパラメータをできるだけ早く定義すると、最適な設計が生まれますearlyコードのフローに関する意味。

当然の結果

  • デザインフローで、オブジェクトの構築時にパラメーター値を知る場合は、コンストラクターへの入力として定義します。それ以外の場合は、それを方法

物語

Premiseを優れたオブジェクト指向設計の公理として使用する場合、Theoremは設計を導くのに役立つ可能性があります。実際には1つあります(クラス名のためだけにオブジェクトに盲目的に名前を付けるのではありません)。

TL; DRバージョンでは、この回答は次のようになっています。設計中の最新の時点でパラメーター値が判明した場合は、メソッドに追加するだけです。事前に知っている場合は、コンストラクターまたは別のメソッドのいずれかで取り出してください。

  • 例1

Pointメソッドを使用してdistanceFromクラスを作成し、別のポイントからの距離を計算します。メソッドdistanceFrom(x, y, xOther, yOther)を持つことは理にかなっていますか?いいえ、その構築時にポイントのxとyを知っていたので、それをコンストラクタに渡すべきでした。したがって、適切なメソッドはdistanceFrom(x,y)(または、より可能性が高いのはdistanceFrom(point))です。

  • 例2(your case

Personからの日数を計算するときは、2つのタイムスタンプを減算する必要があります。それらの1つはnowです。もう1つは過去のある時点です。過去のタイムスタンプはearlierであることがわかっていたため、最適な設計はそれをメソッドに含めないことです。 Personオブジェクトをできるだけ早く過去のタイムスタンプと知り合う方法を見つけてください。できればそれがわかった瞬間に、つまりコンストラクタで、またはPersonオブジェクトの有効期間に沿って変更したい場合はPerson.cameBack(timestamp)の行に沿って別のメソッドを作成し、Personがタイムスタンプにマークを付けて、後でdaysAwayメソッドに使用できるようにします。

0
Vector Zita