2

私は Java で設計していますが、これは一般的な OOP の質問です。私は特定の問題を解決しようとしているわけではなく、いくつかの設計原則について考えてみました。
私の経験から、私はオブジェクトのセットアップを 3 つのフェーズに分離する習慣に達しました。

目標は、余分な作業、難読化されたコード、機能不全の拡張性を最小限に抑えることです。


工事

  1. 有効なオブジェクトを作成するために必要な最小限のアクションは、存在テストに合格します
  2. インスタンス化して初期化するのは「一度だけ」であり、オーバーライドされることはなく、オブジェクトの存続期間中変更/変更されない非変数オブジェクト
  3. 最終メンバーの初期化
  4. 基本的にランタイム スタブ

初期化

  1. オブジェクトを便利にする
  2. パブリックにアクセス可能なメンバーをインスタンス化して初期化する
  3. 変数値であるプライベート メンバーをインスタンス化して初期化する
  4. オブジェクトは、例外を生成することなく外部テストに合格する必要があります (コードが正しいと仮定)

リセット

  1. 何もインスタンス化しない
  2. すべての変数 public/private メンバーにデフォルト値を割り当てます
  3. オブジェクトを正確な状態に戻します

おもちゃの例:

public class TestObject {
   private int priv_a;
   private final int priv_b;
   private static int priv_c;
   private static final int priv_d = 4;

   private Integer priv_aI;
   private final Integer priv_bI;
   private static Integer priv_cI;
   private static final Integer priv_dI = 4;  

   public int pub_a;
   public final int pub_b;
   public static int pub_c;
   public static final int pub_d = 4;

   public Integer pub_aI;
   public final Integer pub_bI;
   public static Integer pub_cI;
   public static final Integer pub_dI = 4;   

   TestObject(){
        priv_b = 2;
        priv_bI = new Integer(2);
        pub_b = 2;
        pub_bI = new Integer(2);
   }

   public void init() {
       priv_a = 1;
       priv_c = 3;
       priv_aI = new Integer(1);
       priv_cI = new Integer(3);

       pub_a = 1;
       pub_c = 3;
       pub_aI = new Integer(1);
       pub_cI = new Integer(3);
   }

   public void reset() {
       priv_a = 1;
       priv_c = 3;
       priv_aI = 1;
       priv_cI = 3;

       pub_a = 1;
       pub_c = 3;
       pub_aI = 1;
       pub_cI = 3;
   }  
}
4

5 に答える 5

2

「init」メソッドが不要になるようにクラスを設計します。クラスのすべてのメソッド、特にパブリック メソッドは、正常に完了した後、オブジェクトが常に「有効な」状態のままであり、他のメソッドを呼び出す必要がないことを保証する必要があると思います。

同じことがコンストラクターにも当てはまります。オブジェクトが作成されると、それは初期化され、使用する準備ができていると見なされる必要があります (これがコンストラクターの目的であり、これを実現するための多くのトリックがあります)。それ以外の場合、安全に使用できる唯一の方法は、オブジェクトが他のすべてのパブリック メソッドの先頭で初期化されているかどうかを確認することです。

于 2009-06-29T11:01:13.843 に答える
1

私は Java とはルールが少し異なる C++ のバックグラウンドを持っていますが、これらの 2 段階の初期化の原則は一般的なケースに当てはまると思います。

工事

  1. 建設時にできることはすべて建設時に行うべきです。
  2. を呼び出す前に、オブジェクトを使用しようとすることによって生じる可能性のある「問題」の量を最小限に抑えますinit()
  3. すべてのメンバー変数には値が必要です。それが通常は無効なセントリー値であっても (たとえば、ポインターを null に設定します)、値が必要です。Javaはデフォルトですべての変数をゼロに初期化すると思うので、それが有効な数値である場合は別のものを選択する必要があります。

初期化

  1. 他のオブジェクトの存在に依存するメンバー変数を初期化します。基本的には施工時にできなかったことをやる。
  2. オブジェクトが完全ですぐに使用できる状態になっていることを確認します。そうでない場合は、例外をスローすることを検討してください。

リセット

  1. そのような関数を呼び出したいときにシステムがどのような状態になるかについて、じっくりと考えてください。その操作がコストがかかると思われる場合でも、新しいオブジェクトをゼロから作成する方がよい場合があります。コードをプロファイリングして、それが問題かどうかを調べます。
  2. 項目 1 を通過したと仮定してreset()、コンストラクターと両方が行う必要があることを処理するメソッドを作成することを検討してください。これにより、メンテナンスが容易になり、コードの重複が回避されます。
  3. オブジェクトを の後と同じ状態に戻しますinit()
于 2009-05-05T17:02:51.337 に答える
0

これとまったく同じパターンを使用したことがあるとは言えませんが、コードの重複を減らすために同様のものを使用しました。たとえば、コンストラクターを介して作成されるか、ファクトリ メソッドを介して別のオブジェクト (DTO など) から作成されるオブジェクトがある場合です。その場合、多くの場合、両方で使用されるオブジェクトのプロパティを設定する内部初期化子を使用します。「リセット」メソッドを使用したことがあるとは言えません。また、新しいオブジェクトを作成するプロセスを複製するだけである場合、実際にその必要があるとは思いません。

最近、デフォルトのコンストラクターのみを使用し、プロパティ セッターを使用してオブジェクトを初期化するようになりました。これを「コンストラクターのような」形式で簡単に実行できる新しい C# 構文により、これがすべて使いやすくなり、パラメーター化されたコンストラクターをサポートする必要性がなくなりました。

于 2009-02-26T23:57:57.057 に答える
0

理由があり、init()異なるreset()必要がありますか?この単純な例では、「何もインスタンス化しない」というルールが重要な理由を理解するのは困難です。

それを超えて、オブジェクトは構築されたらすぐに役立つはずだと思います。何らかの理由 (循環依存または継承の問題) がある場合、構築後にオブジェクト「初期化」する必要がある場合は、コンストラクターと初期化を静的ファクトリ メソッドの背後に隠します。(そして、適切な測定のために、おそらく初期化コードを別のコンフィギュレーター オブジェクトに移動します。)

それ以外の場合は、呼び出し元が常にコンストラクターと の両方を呼び出すことを期待しています。init()これは非標準のパターンです。ここには、それを行う古い、あまりにも便利で捨てられないコードがあります。これは抽象ダイアログ クラスであり、誰かがそれを拡張するたびに呼び出すのを忘れconstructUI()、新しいダイアログが空である理由を考えて 15 分間無駄にします。

于 2009-07-31T13:57:12.663 に答える
0

面白い。この構造は、IO 操作を実行する必要があるオブジェクトがある場合に特に便利です。コンストラクターで直接的または間接的に IO 操作を実行したくありません。オブジェクトを使用するのは悪夢になります。

于 2009-11-25T16:03:55.553 に答える