web-dev-qa-db-ja.com

init()メソッドはコードの匂いですか?

型のinit()メソッドを宣言する目的はありますか?

コンストラクタよりinit()を優先する または init() を宣言しないようにする方法を尋ねているのではありません。

init()メソッドの宣言の背後にany根拠があるかどうか(それがどのくらい一般的であるかを確認)、またはコードかどうかを尋ねていますにおいがするので避けてください。


init()イディオムは非常に一般的ですが、実際の利点はまだわかりません。

メソッドを介した初期化を促進する型について話している:

class Demo {
    public void init() {
        //...
    }
}

これはいつプロダクションコードで使用されますか?


コンストラクターがオブジェクトを完全に初期化せず、部分的に作成されたオブジェクトを生成することを示唆しているため、コードのにおいかもしれないと思います。状態が設定されていない場合、オブジェクトは存在しないはずです。

これは、エンタープライズアプリケーションの意味で、生産をスピードアップするために使用されるある種のテクニックの一部である可能性があると私に思わせます。それが私がそのようなイディオムを持つことを考えることができる唯一の論理的な理由です、もしそうだとしたらそれがどのように有益であるかは分かりません。

20
Vince Emigh

はい、それはコードのにおいです。コードのにおいは、常に削除する必要があるものではありません。それはあなたを再検討させるものです。

ここには、基本的に異なる2つの状態のオブジェクトがあります。初期化前と初期化後です。これらの状態には、さまざまな責任、呼び出しを許可されているさまざまなメソッド、およびさまざまな動作があります。実質的には2つの異なるクラスです。

物理的に2つの別々のクラスにする場合は、潜在的なバグのクラス全体を静的に削除しますが、モデルが「実際のモデル」と非常に厳密に一致しない可能性があります。通常、最初の名前はConfigまたはSetupまたはそのような名前にします。

次回は、あなたのconstruct-initイディオムを2つのクラスのモデルにリファクタリングしてみて、どうなるか見てみましょう。

40
Karl Bielefeldt

場合によります。

initメソッドは、オブジェクトの初期化をコンストラクターから切り離す必要がない場合のコード臭です。これらのステップを分離することが理にかなっている場合があります。

簡単なGoogle検索で this の例が見つかりました。オブジェクトの割り当て中に実行されるコード(コンストラクター)が初期化自体から分離されたほうがよい場合が多いことは容易に想像できます。おそらく、システムが平準化されていて、割り当て/構築はレベルXで行われますが、初期化はレベルYでのみ行われます。Yだけが必要なパラメーターを提供できるためです。おそらく「init」はコストがかかり、割り当てられたオブジェクトのサブセットに対してのみ実行する必要があり、そのサブセットの決定はレベルYでのみ実行できます。または、派生の(仮想)「init」メソッドをオーバーライドしたい場合コンストラクターでは実行できないクラス。たぶん、レベルXは継承ツリーから割り当てられたオブジェクトを提供しますが、レベルYは具体的な派生を認識せず、共通のインターフェイス(initが定義されている可能性がある)についてのみ認識します。

もちろん、私の経験では、これらのケースは、すべての初期化をコンストラクターで直接実行できる標準的なケースのごく一部にすぎません。別のinitメソッドが表示される場合はいつでも、質問することをお勧めしますその必要性。

14
Doc Brown

私の経験は2つのグループに分類されます。

  1. Init()が実際に必要なコード。これは、スーパークラスまたはフレームワークが、クラスのコンストラクターが構築中にすべての依存関係を取得できない場合に発生する可能性があります。
  2. Init()が使用されているが、回避された可能性のあるコード。

私の個人的な経験では、(1)のいくつかのインスタンスだけを見ましたが、(2)のより多くのインスタンスを見ました。したがって、私は通常init()がコードの匂いだと思いますが、これは常にそうだとは限りません。時々それを回避することはできません。

ビルダーパターン を使用すると、多くの場合、init()を使用する必要性/欲望を取り除くのに役立ちます。

6
Ivan

init()メソッドは、他のオブジェクトによって同時に使用される外部リソース(たとえば、ネットワーク接続など)を必要とするオブジェクトがある場合、かなり意味のあるものになります。オブジェクトの存続期間中、リソースを占有する必要がない場合があります。このような状況では、リソースの割り当てが失敗する可能性が高いときに、コンストラクターでリソースを割り当てたくない場合があります。

特に組み込みプログラミングでは、確定的なメモリフットプリントが必要なため、コンストラクターを早期に呼び出し、場合によっては静的に呼び出し、特定の条件が満たされた場合にのみ初期化するのが一般的(良いですか)です。

そのような場合を除いて、すべてをコンストラクタに入れるべきだと思います。

1
tofro

Initメソッドが役立つ典型的なシナリオは、変更する構成ファイルがあり、アプリケーションを再起動せずに変更を考慮に入れる場合です。もちろん、これはInitメソッドをコンストラクタとは別に呼び出す必要があるという意味ではありません。コンストラクターからInitメソッドを呼び出し、構成パラメーターが変更されたときに、後でそれを呼び出すことができます。

まとめると、ほとんどのジレンマは、これがコードのにおいであるかどうかは、状況と状況によって異なります。

1
Vladimir Stokic

それらの使用方法によって異なります。

ヒープ上のオブジェクトを再割り当てし続けたくない場合(ビデオゲームを作成していて、パフォーマンスを高く保つ必要がある場合、ガベージコレクターがパフォーマンスを低下させる場合など)は、Java/C#などのガベージコレクション言語でそのパターンを使用します。コンストラクターを使用して、必要な他のヒープ割り当てを行い、initを使用して、再利用する直前に基本的な有用な状態を作成します。これは、オブジェクトプールの概念に関連しています。

また、初期化命令の共通サブセットを共有するコンストラクターがいくつかある場合にも役立ちますが、その場合、initはプライベートになります。そうすれば、各コンストラクターを可能な限り最小化できるため、各コンストラクターには固有の命令とinitへの1回の呼び出しのみが含まれ、残りを実行できます。

一般的には、それはコードのにおいです。

1
Cody

一般に、関数インスタンスに必要なすべての引数を受け取るコンストラクターを好みます。これにより、そのオブジェクトのすべての依存関係が明確になります。

一方、パラメーターのないパブリックコンストラクターと依存関係と構成値を注入するためのインターフェイスを必要とする単純な構成フレームワークを使用しています。それが完了すると、構成フレームワークはオブジェクトのinitメソッドを呼び出します。これで、私が持っているすべてのものを受け取ったので、最後の手順を実行して作業の準備をします。しかし注意してください:それはあなたがそれを呼び出すことを忘れないように、自動的にinitメソッドを呼び出す設定フレームワークです。

0
Bernhard Hiller

オブジェクトの状態ライフサイクルにinit()メソッドが意味的に埋め込まれている場合、コードの臭いはありません。

オブジェクトを一貫した状態にするためにinit()を呼び出す必要がある場合、それはコードのにおいです。

このような構造が存在するいくつかの技術的な理由があります。

  1. フレームワークフック
  2. オブジェクトを初期状態にリセットする(冗長性を避ける)
  3. テスト中にオーバーライドする可能性
0
oopexpert