オブジェクトインスタンス変数を使用する場合とメソッドに引数を渡す場合


93

メソッドに引数を渡すか、オブジェクトのすべてのメソッドから見えるオブジェクトインスタンス変数として単に引数を宣言するかをどのように決定しますか?

クラスの最後のリストにインスタンス変数を保持することを好みますが、このリストは私のプログラムが大きくなるにつれて長くなります。変数が十分に頻繁に渡されるかどうかは、それを必要とするすべてのメソッドから見えるようにする必要がありますが、「すべてが公開されている場合は、何も渡す必要がまったくありません!」


1
特定の例がある場合は、より直接的に役立つ回答が得られる可能性があります
Brabster

回答:


55

インスタンス変数を参照しているので、私はあなたがオブジェクト指向言語で作業していると想定しています。インスタンス変数をいつ使用するか、そのスコープを定義する方法、およびローカル変数をいつ使用するかはある程度主観的ですが、クラスを作成するときは常に従うことができるいくつかの経験則があります。

  • インスタンス変数は通常、クラスの属性と見なされます。これらは、クラスから作成されるオブジェクトの形容詞と考えてください。インスタンスデータを使用してオブジェクトの説明に役立てることができる場合は、インスタンスデータに適していると考えるのが無難でしょう。

  • ローカル変数は、メソッドのスコープ内で使用され、作業を完了できるようにします。通常、メソッドには、一部のデータを取得する、一部のデータを返す、および/または一部のデータに対してアルゴリズムを処理/実行するという目的があります。場合によっては、ローカル変数をメソッドを最初から最後まで支援する方法として考えると役立ちます。

  • インスタンス変数のスコープは、セキュリティのためだけでなく、カプセル化のためにもあります。「すべての変数をプライベートに保つことが目標である」と想定しないでください。継承の場合、通常、変数を保護されたものにすることは良い選択肢です。すべてのインスタンスデータを公開するのではなく、外部にアクセスする必要のあるインスタンスのゲッター/セッターを作成します。それらすべてを利用可能にするのではなく、必要なものだけを利用してください。これは、開発ライフサイクル全体を通じて行われます-最初から推測するのは困難です。

クラスの周りでデータを渡すことになると、コードを確認せずに、何をしているのかを判断するのは困難です。場合によっては、インスタンスデータを直接操作しても問題ありません。それ以外の場合は、そうではありません。私の意見では、これは経験に伴うものです。オブジェクト指向の思考スキルが向上するにつれて、いくつかの直感が発達します。


私の答えは、この答えをH-Man2の答え(寿命)に追加することです。オブジェクトの永続的な状態である場合にのみ、メンバー属性にする必要があります。つまり、この値は、それ自体が現在のメソッドスタックのスコープ外では意味があります。
デビッドロドリゲス-ドリベス2008

私の直感的な反応は、DavidとH-MAn2に同意することです。しかし、私はRobert c Martinによる「クリーンなコード」を読んでおり、第3章では、メソッドパラメーターからメンバー変数に何かを移動するようにコードをリファクタリングしています。結局のところ、クラスの責任が1つだけの場合、オブジェクトの存続期間はその計算の存続期間と同じであるため、実際の答えは、この質問をしなければならない場合、クラスが大きすぎるということでしょうか。
アンディ

@DavidRodríguez-dribeasメソッドスタックとはどういう意味ですか?
CommittedAndroider

@committedandroider:値は、現在の関数呼び出しoutlives場合
dribeas -デビッド・ロドリゲス

46

これは主に、変数に格納するデータの寿命に依存します。データが計算中にのみ使用される場合は、パラメーターとして渡します。データがオブジェクトの存続期間にバインドされている場合は、インスタンス変数を使用します。

変数のリストが長くなりすぎた場合は、クラスの一部を新しいクラスにリファクタリングすることを検討することをお勧めします。


21

私の意見では、インスタンス変数は、データが呼び出し間で使用される場合にのみ必要です。

次に例を示します。

myCircle = myDrawing.drawCircle(center, radius);

ここで、myDrawingクラスのイメージングで15のヘルパー関数を使用してmyCircleオブジェクトを作成します。これらの各関数には中心と半径が必要です。それでも、myDrawingクラスのインスタンス変数として設定しないでください。それらが再び必要になることは決してないからです。

一方、myCircleクラスは、インスタンス変数として中心と半径の両方を格納する必要があります。

myCircle.move(newCenter);
myCircle.resize(newRadius);

これらの新しい呼び出しが行われたときにmyCircleオブジェクトが半径と中心を認識するためには、それらを必要とする関数に渡すだけでなく、インスタンス変数として保存する必要があります。

したがって、基本的に、インスタンス変数はオブジェクトの「状態」を保存する方法です。変数がオブジェクトの状態を知る必要がない場合は、インスタンス変数であってはなりません。

そしてすべてを公開することに関しては。それはあなたの人生を一瞬で楽にするかもしれません。しかし、それはあなたを悩ませるために戻ってきます。やめてください。


ただし、パラメータ(oldCenter、newCenter)を使用するようにmoveを定義することもできます。
obesechicken13

4

私見では:

変数がインスタンスの状態の一部を形成する場合、それはインスタンス変数である必要があります-クラスインスタンスHAS-Aインスタンス変数。

インスタンスのメソッドに何かを繰り返し渡すことに気付いた場合、またはインスタンス変数が多数あることに気付いた場合、何かを見落としたり、どこかに悪い抽象化をしたりした場合に備えて、デザインを調べてみます。

それが役に立てば幸い


3

もちろん、クラスにパブリック変数の大きなリストを1つ保持するのは簡単です。しかし、直感的にも、これは進むべき道ではないことがわかります。

使用する直前に各変数を定義します。変数が特定のメソッドの機能をサポートする場合は、メソッドのスコープ内でのみ使用してください。

セキュリティについても考慮してください。パブリッククラス変数は、「外部」コードからの不要な変更の影響を受けやすくなっています。あなたの主な目標は、すべての変数をプライベートに保つことであり、そうでない変数は、プライベートであることに十分な理由があるはずです。

スタック全体に渡るパラメーターの受け渡しについては、これは非常に速く醜くなります。経験則では、メソッドシグネチャをクリーンでエレガントに保つことです。同じデータを使用する多くのメソッドが表示される場合は、クラスメンバーであることが重要であるかどうかを判断し、そうでない場合は、コードをリファクタリングしてより意味のあるものにします。

それは、常識に要約されます。それぞれの新しい変数を宣言する場所と理由を正確に考え、関数はどうあるべきかを考え、そこから、変数をどのスコープに含めるかを決定します。


メソッドを公開してユニットテストを行えるようにすることもよくあります。
obesechicken13
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.