30

私はC#でプロジェクトに取り組んでいます。以前のプログラマーはオブジェクト指向プログラミングを知らなかったので、ほとんどのコードは巨大なファイル (約 4 ~ 5000 行) にあり、数十、場合によっては数百のメソッドにまたがっていますが、クラスは 1 つだけです。このようなプロジェクトをリファクタリングするのは大変な作業です。

いずれかのコード ファイルでメソッドが使用されるたびに、クラスがインスタンス化され、オブジェクト インスタンスでメソッドが呼び出されます。

この方法でパフォーマンスに顕著なペナルティがあるかどうか疑問に思っていますか? 「今のところ」すべてのメソッドを静的にする必要がありますか?最も重要なのは、アプリケーションが何らかの方法でそれから恩恵を受けるかどうかです。

4

8 に答える 8

28

ここから、静的呼び出しは、インスタンス メソッドを呼び出すたびにインスタンスを構築するよりも 4 ~ 5 倍高速です。ただし、呼び出しごとに数十ナノ秒しか話していないため、メソッドを何百万回も呼び出す非常にタイトなループがない限り、利点に気付く可能性は低く、外部で単一のインスタンスを構築することで同じ利点を得ることができますそのループとそれを再利用します。

新しく静的なメソッドを使用するには、すべての呼び出しサイトを変更する必要があるため、時間をかけて徐々にリファクタリングする方がよいでしょう。

于 2008-10-14T21:02:11.023 に答える
10

私が働いている場所で同様の問題に対処しました。私の前のプログラマーは、すべての BLL 関数がダ​​ンプされた 1 つのコントローラー クラスを作成しました。

現在、システムを再設計しており、制御対象に応じて多くの Controller クラスを作成しています。

UserController、GeographyController、ShoppingController...

各コントローラー クラス内には、シングルトン パターンを使用してキャッシュまたは DAL を呼び出す静的メソッドがあります。

これにより、2 つの主な利点が得られました。わずかに高速です(約2〜3倍高速ですが、ここではナノ秒でした;P)。もう 1 つは、コードがはるかにクリーンであることです。

すなわち

ShoppingController.ListPaymentMethods()

それ以外の

new ShoppingController().ListPaymentMethods()

クラスが状態を維持しない場合は、静的メソッドまたはクラスを使用するのが理にかなっていると思います。

于 2008-12-25T03:16:51.060 に答える
7

そのオブジェクトに他に何が含まれているかによって異なります。「オブジェクト」が単なる関数の集まりである場合、それはおそらく世界の終わりではありません。ただし、オブジェクトに他のオブジェクトが多数含まれている場合、インスタンス化するとすべてのコンストラクター (および削除された場合はデストラクタ) が呼び出され、メモリの断片化などが発生する可能性があります。

とはいえ、現在、パフォーマンスが最大の問題であるようには思えません。

于 2008-10-15T03:08:49.147 に答える
6

書き換えの目標を決定する必要があります。テスト可能、拡張可能、保守可能な優れた OO コードが必要な場合は、オブジェクトとそのインスタンス メソッドを使用してみてください。結局のところ、これは私たちがここで話しているのはオブジェクト指向プログラミングであり、クラス指向プログラミングではありません。

インターフェイスを実装するクラスを定義し、インスタンス メソッドを実行する場合、オブジェクトをフェイクまたはモックするのは非常に簡単です。これにより、徹底的な単体テストが迅速かつ効果的に行われます。

また、適切なオブジェクト指向の原則 ( http://en.wikipedia.org/wiki/SOLID_%28object-directional_design%29の SOLID を参照) に従うか、デザイン パターンを使用する場合は、多くのインスタンス ベースを使用することになります。 、インターフェースベースの開発、および多くの静的メソッドを使用しない。

この提案について:

オブジェクトに副作用がないように見えるメソッドを呼び出すことができるように、オブジェクトを作成するのはばかげているように思えます(あなたの説明から、これを想定しています)。

これはドット ネット ショップでよく見かけますが、私にとってこれは、主要な OO の概念であるカプセル化に違反しています。メソッドが静的であるかどうかによって、メソッドに副作用があるかどうかを判断できないはずです。これは、カプセル化を解除するだけでなく、メソッドを変更して副作用がある場合は、メソッドを静的からインスタンスに変更する必要があることを意味します。これについては、オープン/クローズドの原則を読んで、上で引用した提案されたアプローチがそれを念頭に置いてどのように機能するかを確認することをお勧めします。

「時期尚早の最適化は諸悪の根源である」ということを思い出してください。この場合、これは、パフォーマンスの問題があることがわかるまで、不適切な手法 (つまり、クラス指向プログラミング) を使用してフープを飛び越えないことを意味すると思います。それでも問題をデバッグし、最も適切なものを探します。

于 2012-01-17T12:38:12.437 に答える
6

静的メソッドははるかに高速であり、使用するメモリも大幅に少なくなります。少しだけ速いという誤解があります。ループにしない限り、少し速くなります。ところで、一部のループは小さく見えますが、ループを含むメソッド呼び出しも別のループであるため、実際にはそうではありません。レンダリング機能を実行するコードの違いを見分けることができます。残念ながら、多くの場合、メモリがはるかに少ないことが当てはまります。インスタンスを使用すると、姉妹メソッドと簡単に情報を共有できます。静的メソッドは、必要なときに情報を要求します。

しかし、車の運転と同じように、スピードには責任が伴います。通常、静的メソッドには、対応するインスタンスよりも多くのパラメーターがあります。インスタンスが共有変数のキャッシュを処理するため、インスタンス メソッドはより見栄えがよくなります。

ShapeUtils.DrawCircle(stroke, pen, origin, radius);

ShapeUtils.DrawSquare(stroke, pen, x, y, width, length);

VS

ShapeUtils utils = new ShapeUtils(stroke,pen);

util.DrawCircle(origin,radius);

util.DrawSquare(x,y,width,length);

この場合、ほとんどの場合、インスタンス変数がすべてのメソッドで使用されるときはいつでも、インスタンス メソッドは非常に価値があります。インスタンスは状態についてではなく、共有についてのものですが、共通状態は共有の自然な形であり、同じではありません。一般的な経験則は次のとおりです。メソッドが他のメソッドと密接に結合されている場合 --- お互いに愛し合っているため、一方が呼び出されたときにもう一方も呼び出す必要があり、おそらく同じカップの水を共有します --ー、インスタンス化すればいいのに。静的メソッドをインスタンス メソッドに変換することは、それほど難しくありません。共有パラメータを取得してインスタンス変数として配置するだけです。その逆は難しいです。

または、静的メソッドをブリッジするプロキシ クラスを作成することもできます。理論上は効率が悪いように見えるかもしれませんが、実際にやってみると話は別です。これは、DrawSquare を 1 回 (またはループで) 呼び出す必要がある場合は常に、静的メソッドに直接アクセスするためです。ただし、DrawCircle と一緒に何度も使用する場合は、インスタンス プロキシを使用することになります。例として、System.IO クラスの FileInfo (インスタンス) と File (静的) があります。

静的メソッドはテスト可能です。実際、インスタンス ワンスよりもさらにテスト可能です。メソッド GetSum(x,y) は、単体テストだけでなく、負荷テスト、統合テスト、および使用テストにも非常に適しています。インスタンス メソッドは単体テストには適していますが、他のすべてのテスト (これは単体テストよりも重要です) にとってはひどいものです。そのため、最近非常に多くのバグが発生しています。すべてのメソッドをテスト不可能にするのは、(Sender s、EventArgs e) のような意味をなさないパラメーターや、DateTime.Now のようなグローバル状態です。実際、静的メソッドはテスト容易性に非常に優れているため、新しい Linux ディストリビューションの C コードに見られるバグは、平均的な OO プログラマーよりも少なくなります (彼は s*** でいっぱいです)。

于 2014-11-09T11:14:44.853 に答える
3

私はあなたがそれを尋ねた方法でこの質問に部分的に答えたと思います:あなたが持っているコードに顕著なパフォーマンスのペナルティはありますか?

ペナルティが目立たない場合は、必ずしも何もする必要はありません。(言うまでもなく、コードベースは、立派なOOモデルへの段階的なリファクタリングから劇的に恩恵を受けるでしょう)。

私が言っているのは、パフォーマンスの問題は、それが問題であることに気付いたときだけの問題だと思います。

于 2008-10-14T21:08:04.210 に答える
2

オブジェクトに副作用がないように見えるメソッドを呼び出すことができるように、オブジェクトを作成するのはばかげているように思えます(あなたの説明から、これを想定しています)。より良い妥協点は、いくつかのグローバル オブジェクトを持ち、それらを使用することです。そうすれば、通常はグローバルである変数を適切なクラスに配置して、スコープをわずかに小さくすることができます。

そこから、適切な OOP 設計が得られるまで、これらのオブジェクトのスコープを徐々に小さくしていくことができます。

繰り返しますが、私がおそらく使用するアプローチは異なります;)。

個人的には、構造体とそれを操作する関数に注目して、少しずつメンバを持つクラスに変換してみようと思います。

質問のパフォーマンスの側面に関しては、静的メソッドはオブジェクトの構築、受け渡し、および分解を含まないため、わずかに高速である必要があります (ただし、それほど高速ではありません)。

于 2008-10-14T20:26:36.510 に答える