Возможно, синглетон является простейшим дизайном проектирования, который является способом обеспечения одного и только одного объекта определенного типа. Важнейший аспект Синглетона заключается в том, что вы предоставляете глобальную точку доступа, так что синглетон часто является решением, которое вы получали при использовании глобальных переменных в C. В дополнение, синглетон часто имеет характер реестра или поискового сервиса - это место, в котором вы ищите ссылки на другие объекты.

Синглетоны могут быть найдены и библиотеках Java, но здесь приведен более направленный пример:

//: синглетон:SingletonPattern.java
// Шаблон дизайна Синглетон: вы никогда
// не сможете создать более одного экземпляра.
package singleton;

import junit.framework.*;

// Так как здесь нет наследования от базового
// класса Cloneable, то размножаемость (клонируемость) не добавлена,
// модификатор final предотвращает добавление размножения
// посредством наследования:
final class Singleton {
  
private static Singleton s = new Singleton(47);
  
private int i;
  
  
private Singleton(int x) {
     
i = x;
  
}
  
  
public static Singleton getReference() {
     
return s;
  
}
  
  
public int getValue() {
     
return i;
  
}
  
  
public void setValue(int x) {
     
i = x;
  
}
}

public class SingletonPattern extends TestCase {
  
public void test() {
     
Singleton s = Singleton.getReference();
      String result =
"" + s.getValue();
      System.out.println
(result);
      assertEquals
(result, "47");
      Singleton s2 = Singleton.getReference
();
      s2.setValue
(9);
      result =
"" + s.getValue();
      System.out.println
(result);
      assertEquals
(result, "9");
     
try {
        
// Не могу сделать это: ошибка времени компиляции.
         // Singleton s3 = (Singleton)s2.clone();
     
}
     
catch (Exception e) {
        
throw new RuntimeException(e);
     
}
   }
  
  
public static void main(String[] args) {
     
junit.textui.TestRunner.run(SingletonPattern.class);
  
}
}
// /:~

Основной смысл при создании синглетона в том, чтобы у клиентского программиста не было возможности создать объект за исключением той, которую вы ему предоставили. Вы должны сделать все конструкторы частными (private) и вы должны создать хотя бы один конструктор, чтобы запретить компилятору синтезировать конструктор по умолчанию за вас (который будет создан, используя пакетный доступ).

В этом месте вы решаете, как вам создавать объект. В данном случае он создан статически, но вы можете также подождать, пока клиентский программист запросит объект, и создадите его по запросу. В любом случае, объект должен храниться недоступным образом. Вы обеспечиваете доступ через публичные методы. В данном случае getReference() предоставляет ссылку на объект Singleton. Остальная часть интерфейса (getValue() и setValue()) - это обычный интерфейс класса.

Java также позволяет создавать объекты с помощью клонирования. В этом примере модификатор final предотвращает клонирование. Так как Singleton наследуется напрямую от Object, метод clone() остается в разделе protected, так что он не может быть использован (его использование вызывает ошибку времени компиляции). Однако, если вы наследуете от иерархического класса, который уже перегрузил метод clone(), сделав его публичным через реализацию Clonable, есть способ предотвратить клонирование с помощью перегрузки метода clone(), который будет выбрасывать CloneNotSupportedException, как это описано в приложении А Thinking in Java, 2nd edition. (Вы можете также перегрузить метод clone() и просто возвращать this, но это может быть обманчивым, так как клиентский программист будет думать, что он клонировал объект, но вместо этого будет иметь дело с оригиналом этого объекта.) На самом деле, это не абсолютная правда, потому что даже в приведенной выше ситуации кто-либо может использовать рефлексию, чтобы вызвать clone() (не правда ли? clone() все еще является защищенным (protected), так что я не совсем уверен. Если это так, вы должны выбрасывать CloneNotSupportedException, как единственный способ гарантии не клонируемости.)

Упражнения

  1. SingletonPattern.java всегда создает объект, даже если он никогда не будет использован. Измените эту программу, использующую ленивую инициализацию, таким образом, чтобы объект синглетона создавался только при первой необходимости.
  2. Создайте службу реестра/поиска, которая принимает интерфейс Java и производит ссылку на объект, который реализует этот интерфейс.