質問

次のクラス:

class Pizza {

    Ingredients ingredients;
    Price price;

    public setIngredients(Ingredients ing) {
        if (ingredients != null) {
            throw new IllegalStateException();
        }
        ingredients = ing;
        return this;
    }

    public setPrice(Price p) {
        if (price != null) {
            throw new IllegalStateException();
        }
        price = p;
        return this;
    }

}

ビルダーパターンで使用でき、構築された後、 効果的に不変, 、各プロパティは一度だけ設定できるためです。あれは:

Pizza pizza = new Pizza().setIngredients(something).setPrice(somethingelse);

でも、 Pizza スレッドは安全ではありません:スレッドBがスレッドAによって設定された成分を見るという保証はありません。それを修正する方法はいくつかあります。

  • メンバーを作成します final. 。ただし、ビルダーパターンを使用することはできません。
  • メンバーへのアクセスを同期します。しかし、これは無駄のように思えます。なぜなら、彼らは一度だけ書かれているからです。
  • それらを作ります volatile. 。同期のような無駄を感じます。
  • 使用する AtomicReference.
  • 等。?

私の質問は、何らかの方法が呼び出された後にクラスのメンバーが変わらないことをJVMに伝える最良の方法は何ですか?アクセスを同期するだけで、JVMがロックを最適化することを信頼する必要がありますか?私はただ無駄を感じています 知る メンバー したほうがいい そのように振る舞います final 設定された後。より良い解決策はありませんか?

役に立ちましたか?

解決

ビルダーパターンは通常、ビルダーが別のオブジェクトであることを意味します。この場合、構築されているオブジェクトのフィールドを作成できます final, 、およびビルダーオブジェクトで呼ばれるコンストラクターでそれらを初期化します。

Pizza pizza = 
    new PizzaBuilder()
        .setIngredients(something)
        .setPrice(somethingelse)
        .build(); 

または、の安全な公開を確保することができます Pizza 物体。安全な出版物イディオムは、そのオブジェクト自体のフィールドではなく、公開されているオブジェクトへの参照を含むフィールドに適用されることに注意してください。たとえば、if pizza いくつかのオブジェクトのフィールドです、あなたはそれを作ることができます volatile またはそれへのアクセスを同期する - それはの安全な公開を保証するでしょう Pizza そのフィールドに割り当てられたオブジェクト。

他のヒント

メンバー値が変更されることを意味しない場合、より良いパターンは Pizza パラメーターとして取得するコンストラクター IngredientsPrice, 、そしてオブジェクトにセッターメソッドがまったくありません。本当にありません setSomething() 初めて呼び出された後に例外をスローする方法。

方法を考えてください String クラスの作品。インスタンス化したらa String いくつかのテキストでは、テキスト値を変更できません。取得する唯一の方法 String 異なる値では、新しい値を構築することです。それがあなたがここに望むもののようです。

このパターンを使用すると、同期の問題も回避されます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top