Обеспечение видимости памяти с помощью компоновщика / фабричного шаблона - PullRequest
1 голос
/ 21 марта 2011

Следующий класс:

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 после его установки.Нет ли лучшего решения?

Ответы [ 2 ]

5 голосов
/ 21 марта 2011

Образец строителя обычно означает, что строитель является отдельным объектом.В этом случае вы можете создать поля строящегося объекта final и инициализировать их в конструкторе, вызываемом объектом конструктора:

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

В качестве альтернативы, вы можете обеспечить безопасную публикацию объекта Pizza.Обратите внимание, что идиомы безопасной публикации применяются к полю, содержащему ссылку на публикуемый объект, а не к полям самого объекта.Например, если pizza является полем какого-либо объекта, вы можете сделать его volatile или синхронизировать доступ к нему - это обеспечит безопасную публикацию Pizza объекта, назначенного этому полю.

1 голос
/ 21 марта 2011

Если значения элементов никогда не предназначены для изменения, лучшим вариантом будет иметь конструктор Pizza, который принимает в качестве параметров Ingredients и Price, и вообще не имеет методов установки объекта. На самом деле бесполезно иметь метод setSomething(), который выдает исключение после первого вызова.

Рассмотрим, как работает класс String. После создания экземпляра String с некоторым текстом текстовое значение не может быть изменено. Единственный способ получить String с другим значением - это создать новое. Похоже, это то, что вы хотите здесь.

Использование этого шаблона также позволяет избежать проблемы синхронизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...