Есть ли Singleton в Golang?

от автора

Давайте начнем с определения из Википедии.

“Одиночка (англ. Singleton) — порождающий шаблон проектирования, гарантирующий, что в однопоточном приложении будет единственный экземпляр некоторого класса, и предоставляющий глобальную точку доступа к этому экземпляру.”

“Единственный экземпляр некоторого класса” означает что нет возможности написать код, в котором объект может быть скопирован или создан еще каким-либо способом.

В этом посте про «гарантирующий».

Рассмотрим общеизвестную реализацию. Поле в структуре — для лучшей визуализации результата.

type Singleton struct {  id int  }  var (  instance *Singleton  once     sync.Once  )  func GetInstance() *Singleton {  once.Do(func() {  instance = &Singleton{1}  })  return instance  }

Протестируем его.

func main() {  // first object  s1 := GetInstance()  fmt.Printf("type: %T, value: %v, ptr: %p\n", s1, s1, s1)   // second object. Copying  s2 := *s1  s2.id = 2  fmt.Printf("type: %T, value: %v, ptr: %p\n", s2, s2, &s2)  // third object     s3 := new(Singleton)  s3.id = 3  fmt.Printf("type: %T, value: %v, ptr: %p\n", s3, s3, s3)  // many different objects  for i := 4; i < 8; i++ {  s := Singleton{i}  fmt.Printf("type: %T, value: %v, ptr: %p\n", s, s, &s)  }  }

Результат:

type: *main.Singleton, value: &{1}, ptr: 0xc0000b4000  type: main.Singleton, value: {2}, ptr: 0xc0000b4018  type: *main.Singleton, value: &{3}, ptr: 0xc0000b4020  type: main.Singleton, value: {4}, ptr: 0xc0000b4030  type: main.Singleton, value: {5}, ptr: 0xc0000b4038  type: main.Singleton, value: {6}, ptr: 0xc0000b4040  type: main.Singleton, value: {7}, ptr: 0xc0000b4048

Вывод: создано неограниченное количество объектов!

Немного рассуждений.

Почему-то реализация паттерна в Go указывает программисту пользоваться функцией GetInstance().

А как следует из определения паттерна это должно быть не словесное правило, а сама реализация типа не должна позволять создать более одного экземпляра.

Если использовать словесные правила для программистов, то реализация паттерна могла бы быть и такой: «Не создавайте более одного экземпляра.» И код писать не надо. )

Сравним с реализацией на языке С++.

Все конструкторы и оператор копирования или спрятаны в private секции, или удалены. Или сразу оба способа.

В секции public только один метод — GetInstance(). Нет никаких вариантов создать более одного объекта.

class Singlеton  {  public:          static Singleton& GetInstance()          {                  static Singleton theSingleInstance;                  return theSingleInstance;          }  private:                   Singleton(){}          Singleton(const Singleton& root) = delete;          Singleton& operator=(const Singleton&) = delete;  };

Совсем другая картина в Go.

В тесте видно, что легитимными способами возможен не «единственный экземпляр некоторого класса».

«Для создания объекта используйте GetInstance()» — слабый аргумент. Программист может не знать что этот тип должен быть Singleton‑ом и создать много экземпляров другими способами. А паттерн как раз и нужен для того, чтоб гарантированно исключить «не один экземпляр» в любом случае.


ссылка на оригинал статьи https://habr.com/ru/articles/778378/