web-dev-qa-db-ja.com

インスタンス変数が多すぎると、コードが重複するのはなぜですか?

パターンへのリファクタリング によると:

クラスが多くのことを実行しようとすると、多くの場合、インスタンス変数が多すぎて表示されます。 クラスのインスタンス変数が多すぎる場合、重複したコードが大幅に遅れることはありません。

インスタンス変数が多すぎると、コードが重複するのはなぜですか?

19
q126y

インスタンス変数が多すぎても、コードの重複に直接関係することはなく、その逆も同様です。このステートメントは、この一般性においては誤りです。重複するコードのない2つのクラスを1つのクラスに投げることができます。これにより、責任が分離されず、インスタンス変数が多すぎる新しいクラスが生成されますが、重複するコードはありません。

しかし、実際のレガシーコードで責任のあるクラスが多すぎるクラスを見つけた場合、それを書いたプログラマはクリーンなコードやSOLIDの原則を気にしていませんでした(少なくとも、現時点では)彼がそのコードを書いたとき)、そのため、そこに重複コードのような他のコードのにおいが見つかることはまずありません。

たとえば、「コピーと貼り付けの再利用」アンチパターンは、適切なリファクタリングを行わずに、古いメソッドをコピーして少し変更することで適用されることがよくあります。これを機能させるために、メンバー変数を複製し、その変数を少し変更する必要がある場合もあります。これはmightの結果、インスタンス変数が多すぎるクラスになります(より正確には、非常によく似たインスタンス変数が多すぎます)。このような状況では、同様のインスタンス変数が、クラス内の他の場所で繰り返されているコードのインジケータになる可能性があります。しかし、あなたが指摘したように、これは人工的な例であり、私はそれから一般的なルールを結論づけることはしません。

23
Doc Brown

インスタンス変数が多すぎると、状態が多すぎます。状態が多すぎると、コードが重複し、各状態でわずかに異なるだけです。

これは、サブクラスまたはコンポジションである必要がある多くのことを行う古典的な単一の具象クラスです。

インスタンス変数が多すぎるクラスをいくつか見つけます。それらは、状態を維持しすぎており、重複するコードパスが多く、それぞれの場合にわずかに特殊化されていますが、再利用可能なメソッドに分解できないほど複雑です。これもside effectsの最大のソースの1つです。

これには、このカテゴリに分類されない例外が少なくとも1つあり、これを修正する簡単な方法です。 Immutableobjectsは固定状態であるため、この問題はありません。複雑な状態管理や副作用の可能性はありません。

11
user7519

あなたが引用する声明は、特定の文脈で見られることを意図しています。

私の経験によれば、「多くのインスタンス変数は一般に重複したコードを示している」とは確認できません。また、これは「コードのにおい」に属するものであり、相反する臭いがあるとされています。ここを見てください:

http://c2.com/cgi/wiki?CodeSmell

おもしろいことに、「インスタンス変数が多すぎる」と「インスタンス変数が少なすぎる」というコードの匂いが同じです。

しかし、インスタンス変数には問題があります。少なすぎても多すぎてもかまいません。

  1. すべてのインスタンス変数は、オブジェクトのある種のステータスを意味する場合があります。スタティは常に注意深い治療を必要とします。予期しない動作を回避するために、すべての可能なstatiの組み合わせをカバーしていることを確認する必要があります。あなたはいつもはっきりと今しなければなりません:私のオブジェクトは今どのステータスにありますか?この観点から見ると、多くのインスタンス変数は、クラスが保守できなくなっていることを示している可能性があります。また、クラスは非常に多くの統計を必要とするため、クラスがあまりにも多くの仕事をしていることを示している可能性もあります。

  2. すべてのインスタンス変数は、監視する必要があります。どのメソッドが変数をどのように変更するかです。だから、突然、あなたはもはや料理している料理人のすべてを知りません。そのうちの1つは、深夜に疲れてプログラムされており、スープを台無しにします。繰り返しになりますが、そのような変数が多すぎると、コードの侵入が難しくなります。

  3. 反対側:インスタンス変数が少なすぎると、多くのメソッドが多くの作業とパラメータを使用して情報を処理しなければならない場合があります。多くのメソッドに特定の等しいパラメーターを与え、すべてのメソッドがこのパラメーターを使用して非常によく似た動作をする場合、これを感じます。そのような状況では、コードが肥大化し始めます。いくつかの簡単なものをまとめるために、多くの画面を上下にスクロールすることになります。ここでは、リファクタリングが役立ちます。1つのインスタンス変数と1つの明確な入り口を導入します。次に、すべてのメソッドを解放します。

  4. 最後になりましたが、クラスの多くのインスタンス変数にセッターとゲッターがそれぞれある場合、他のクラスがこの最初のクラスを正しい方法で使用していないことを示している可能性があります。 「 なぜゲッターとセッターが悪いのか 」についての議論があります。つまり、クラスRectangleがいくつかのgetX()を提供し、他の数十のクラスがrectangle.getX()を使用している場合、「リップル効果」(コードの変更が他のコードに影響を与える程度)。タイプをintからdoubleに変更するとどうなるかを尋ねるだけです。この説明によると、rectangle.getX()呼び出しの多くは、実際にはrectanlge.calculateThisThingForMe()のような呼び出しである必要があります。したがって、非常に間接的に、複製されたコードは多くのインスタンス変数から出現する可能性があります。周りの多くのクラスは、非常によく似た動作、つまりコピーされた動作を行う多くのゲッターとセッターを使用するため、クラス内に移動する必要があります。

多くまたは少数のインスタンス変数は、永続的なトレードオフのままであり、ソフトウェアの成長中に両方の方法を変更します。

7
peter_the_oak

簡単に言えば、コード内の懸念の分離が不十分で、モジュール化されていないコードにつながり、再利用が不十分になり、コードの重複につながります。

機能を繰り返そうとしないのであれば、コードの重複や多くのインスタンス変数が問題になることはありません。

機能を繰り返そうとすると、モジュール式ではないモノリシックコードを再利用できません。やりすぎて、できることしかできません。似ているが同じではないことを行うには、モノリシックコードを分割するよりも、カットアンドペーストする方が「簡単」です。経験プログラマーは、重複したコードが地獄への道であることを知っています。

したがって、多くのインスタンス変数自体は問題の根本的な原因ではありませんが、問題が発生していることは強い「におい」です。

「絶対に後れを取ってはならない」という言葉は「必ず守らなければならない」と言うよりも弱いので、作者はそれは必ず起こると主張していませんが、最終的には起こるでしょう。機能を再利用する必要があるが、コードがモジュール化されていないためできない場合。

6
simbo1905