Синглтон-тест не работает, когда var создается с помощью * - PullRequest
0 голосов
/ 11 июня 2019

Я следую шаблону проектирования Singleton, как описано в этой книге (https://github.com/PacktPublishing/Go-Design-Patterns/blob/master/Chapter02/main.go), и у меня есть этот код в файле "singleton2.go":

package singleton2

type Singleton interface {
  AddOne() int
}

type singleton struct {
  count int
}

//var instance = &singleton{}
var instance *singleton

func GetInstance() *singleton {
  if instance == nil {
    return new(singleton)
  }
  return instance
}

func (s *singleton) AddOne() int {
  s.count++
  return s.count
}

Затем у меня есть этот тестfile (singleton2_test.go):

package singleton2

import "testing"

func TestGetInstance(t *testing.T) {
  counter1 := GetInstance()
  if counter1 == nil {
    t.Fatal("expected pointer to Singleton after calling GetInstance(), not nil")
  }

  expectedCounter := counter1

  currentCount := counter1.AddOne()
  if currentCount != 1 {
    t.Errorf("After calling for the first time to count, the counter must be 1 but it is %d", currentCount)
  }

  counter2 := GetInstance()
  if counter2 != expectedCounter {
    t.Errorf("Expected same instance in counter2 but it got a different instance.")
    t.Logf("Got %v, want %v", counter2, expectedCounter)
  }

  currentCount = counter2.AddOne()
  if currentCount != 2 {
    t.Errorf("After calling AddOne() using second counter, the count must be 2, but it was %d", currentCount)
  }

}

Проблема в том, что тесты всегда терпят неудачу:

--- FAIL: TestGetInstance (0.00s)
    singleton2_test.go:20: Expected same instance in counter2 but it got a different instance.
    singleton2_test.go:21: Got &{0}, want &{1}
    singleton2_test.go:26: After calling AddOne() using second counter, the count must be 2, but it was 1
FAIL
exit status 1
FAIL    github.com/d3c3/design_patterns/singleton/singleton2    0.029s

Интересно, если я изменю эту строку var instance *singleton на эту строку var instance = &singleton{} testspass!? Почему это так? ИМО, он должен работать также с "var instance * singleton"

Может кто-нибудь объяснить эту разницу в поведении?

1 Ответ

5 голосов
/ 11 июня 2019

Следуйте логике вашего кода, и очевидно, в чем проблема.

Когда вы объявляете, но не инициализируете синглтон (var instance *singleton), тогда instance равно nil. Вызов GetInstance оценивает instance == nil как true и возвращает новый *singleton каждый раз, когда он вызывается. Вот почему counter2 никогда не будет равно expectedCounter - каждый вызов GetInstance возвращает новый экземпляр счетчика.

Когда вы инициализируете экземпляр синглтона (var instance = &singleton{}), то вызовы GetInstance вернут этот экземпляр синглтона, поскольку это не nil.

Я полагаю, вы захотите изменить GetInstance на что-то вроде этого:

func GetInstance() *singleton {
    if instance == nil {
        instance = new(singleton)
    }
    return instance
}

EDIT

Несмотря на то, что вы не упомянули, что вам нужен этот синглтон, чтобы быть потокобезопасным, пользователь colminator правильно указывает, что создание экземпляра синглтона таким образом может привести к тому, что несколько подпрограмм будут создавать свои собственные экземпляры синглтон, побеждая цель иметь один. Учитывая, насколько плодотворным является параллелизм на Голанге, вероятно, полезно узнать больше! Проверьте ссылку, которую он разместил здесь .

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