2015-06-06 3 views
2

Я читаю об одноэлементном шаблоне из моей книги (Head First Design Patterns), и я знаю, что использование этого шаблона подходит, если вам нужен только один экземпляр некоторого класса.
Но у меня есть небольшая проблема с введением проблемы в этой книге.
(Да, я думаю, что я могу процитировать часть этого здесь!?)Что не так, если вы не используете одноэлементный шаблон

шоколадная фабрика
Всем известно, что все современные шоколадные фабрики с компьютерным управлением шоколадные котлы. Работа котла заключается в том, чтобы принимать шоколад и молоко, доводить их до кипения и , затем передать их на следующий этап изготовления шоколадных батончиков.
Вот класс контроллера для промышленной прочности Choc-O-Holic, Inc. Шоколадный котел. Проверьте код; вы заметите, что они пытались сделать очень осторожны, чтобы не допустить, чтобы плохие вещи не происходили, например, слив 500 галлонов небумажной смеси или заполнение котла, когда он уже заполнен или кипятил пустой котел!

public class ChocolateBoiler { 
    private boolean empty; 
    private boolean boiled; 

    private ChocolateBoiler() { 
     empty = true; 
     boiled = false; 
    } 

    public void fill() { 
     if (isEmpty()) { 
      empty = false; 
      boiled = false; 
      // fi ll the boiler with a milk/chocolate mixture 
     } 
    } 

    public void drain() { 
     if (!isEmpty() && isBoiled()) { 
      // drain the boiled milk and chocolate 
      empty = true; 
     } 
    } 

    public void boil() { 
     if (!isEmpty() && !isBoiled()) { 
      // bring the contents to a boil 
      boiled = true; 
     } 
    } 

    public boolean isEmpty() { 
     return empty; 
    } 

    public boolean isBoiled() { 
     return boiled; 
    } 
} 

Да, и это их вопрос:

Choc-O-Holic сделал приличную работу по обеспечению плохих вещей не случаются, не я думаю ? Опять же, вы, вероятно, подозреваете, что если два случая ChocolateBoiler потерялись, могут произойти некоторые очень плохие вещи.
Как все может пойти не так, если в приложении создано более одного экземпляра ChocolateBoiler ?

Таким образом, проблема «произойдет», когда мы делаем это:

ChocolateBoiler boiler1 = new ChocolateBoiler(), 
boiler2 = new ChocolateBoiler(); 
//... 

Но я вижу, что эти два случая контролировать свое собственное поведение, и они работают независимо друг от друга (потому что не статическое поле здесь).
Таким образом, они запускаются отдельно без эффекта для других.
Интересно, что эта проблема связана с незаконным состоянием или что-то может случиться, когда один экземпляр запускается и воздействует на других («неправильное поведение программы, чрезмерное использование ресурсов или непоследовательные результаты», из книги), но его здесь нет

Итак, How might things go wrong here?, это просто расточительный пример?

если два экземпляра ChocolateBoiler теряют силу, могут возникнуть некоторые очень плохие вещи .

Я хочу видеть, как это происходит bad things?

#Edit 1: Спасибо всем за помощь. Я выяснил, в чем моя проблема,
Когда я звоню boiler2 = new ChocolateBoiler(), экземпляр boiler2 все еще относится к тому же строителю, что и bolder1, не так ли?
Первый раз, когда я думаю, что new ChocolateBoiler() похоже, чтобы купить новый котел :)
Речь идет о концепции, и я новичок здесь

+0

Есть только один котел. Что происходит, когда две вещи пытаются контролировать один котел? –

+0

Да, две вещи пытаются контролировать один котел, могут получить незаконное состояние, но их вопрос связан с проблемой, когда создано более одного экземпляра ChocolateBoiler? – phibao37

+1

Существует один котел с двумя предметами, которые пытаются его контролировать. –

ответ

4

Вы, похоже, не понимаете концепцию, которую этот пример пытается объяснить. ChocolateBoiler не настоящий котел, это класс java.

Однако этот класс может использоваться для указания части оборудования (реального контроллера котла) для выполнения некоторых действий. Если вы ошибочно приняли два экземпляра ChocolateBoiler, и вы ошибочно используете их оба, чтобы проинструктировать один и тот же контроллер котла, то, очевидно, у вас проблемы.

В моем предыдущем абзаце есть два «ошибочно», и вы можете утверждать, что если вы делаете что-то «по ошибке» вообще, то вы все равно в беде. Но в случае плохо спроектированных синглетов ошибки могут быть не столь очевидными. Если вы сериализуете и десериализуете синглтон, который не справляется с проблемами сериализации, чтобы сохранить уникальность, а затем попытайтесь использовать этот экземпляр для нагрева котла, вы можете сжечь котел.

2

Весь смысл использования Singleton шаблон s связан (или можно рассматривать как вариант) Single Source of Truth principle и управление конфликтами. Единственный источник правды - это, конечно, также своего рода управление конфликтами.

Другим аспектом одноэлементных паттернов является необходимость минимизации ненужного дублирования и/или (повторной) инициализации по причинам эффективности.

Например, два отдельных экземпляра будут конфликтовать по одному и тому же ресурсу, что в зависимости от используемого приложения и платформы (например, многопоточности) может привести к возникновению различных проблем, таких как блокировки, недопустимые состояния и т. Д.

Ресурс один (singleton), поэтому менеджер или драйвер для этого ресурса должен учитывать это, чтобы избежать потенциальных конфликтов над одним и тем же ресурсом (см. Выше).

+0

Благодарим за ответ, но можете ли вы объяснить «проблему» в моем примере? – phibao37

+0

два отдельных экземпляра Boiler будут конфликтовать по одному и тому же ресурсу –

+1

, это может привести к возникновению различных проблем (в зависимости от используемого приложения и платформы), таких как взаимоблокировки, недопустимые состояния и т. Д. –

3

Существует несколько проблем с шаблоном Singleton, о котором вы должны знать. Рассмотрим два различных одноэлементные примеры:

1) Stateless одноточечно

Это синглтон не будет иметь членов поля и обеспечить только методы, как услуги для внешнего мира.

public class StatelessSingleton { 

    private static final StatelessSingleton INSTANCE = new StatelessSingleton(); 

    private StatelessSingleton() { 

     // exists to defeat instantiation 
    } 


    public void service() { 
     //... 
    } 

    public void anotherService() { 
     //.. 
    } 

    public StatelessSingleton getInstance() { 
     return INSTANCE; 
    } 
} 

Этот тип одноточечного обычно лучше заменить на класс, который имеет только статические методы, для повышения производительности и удобства чтения. Исключение может быть при реализации шаблона, такого как стратегия, в которой вам нужно реализовать какой-либо интерфейс в качестве алгоритма без учета состояния, поскольку имеет смысл кэшировать эту реализацию. Для реализации интерфейса вам, очевидно, нужен экземпляр.

2) StatefullSingletion

public class StatefullSingleton { 

    private int a = 3; 

    private static final StatefullSingleton INSTANCE = new StatefullSingleton(); 

    private StatefullSingleton() { 

     // exists to defeat instantiation 
    } 


    public void service() { 
     // do some write operation on a 
    } 

    public void anotherService() { 
     // do some read operation on a 
    } 

    public StatefullSingleton getInstance() { 
     return INSTANCE; 
    } 

} 

Теперь, на проблемы с одноплодной:

Оба этих одиночек, когда плохо реализованных может привести к более чем один экземпляр.Пример того, как это может произойти, если бы вы используете блокировки с двойной проверкой в ​​Java, чтобы гарантировать, что только один экземпляр Singleton существует:

class Foo { 
    private Helper helper; 
    public Helper getHelper() { 
     if (helper == null) { 
      helper = new Helper(); 
     } 
     return helper; 
    } 

    // other functions and members... 
} 

Существует много ресурсов, обсуждать, почему это не работает в Java, так что нет нужно повторить это здесь.

Один из способов избежать проблем с двойной проверкой блокировки, как показано выше, с частным конструктором и статической ссылкой на экземпляр + getter.

Вторая проблема, специфичная для StatefullSingelton, заключается в том, что ваши методы обслуживания не синхронизированы, несколько потоков могут испортить состояние такого Singleton. В вашем примере, если разные работники одновременно заполняют и сливают котлы, что-то может пойти не так.

Третий выпуск - сериализация. Учитывая, что Singleton реализует интерфейс java.io.Serializable, это может привести к тому, что при десериализации будет иметься больше одного синглтона. Чтобы избежать создания нового объекта при десериализации, необходимо выполнить readResolve.

+0

хороший анализ на Java-реализации singleton patt erns –

Смежные вопросы