Ленивый синглтон со свойством, которое ссылается на родителя в конструкторе

1

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

Конечный результат, является Context.Current объектом, который служит в качестве точки отсчета для многих функций.

Проблема, с которой я сталкиваюсь, - это свойство этого объекта, который называется классом Providers. Это дает мне информацию OAuth, такую как ClientId, о серии поставщиков облачных вычислений.

ClientIds меняются в зависимости от конечной точки для большинства поставщиков, поэтому в конструкторе для каждого провайдера я проверяю... вы уже догадались, Context.Current.DeploymentType который является ENUM который сообщает мне, в какой среде я нахожусь.

Вызов объекта во время его создания - довольно плохая форма, и я получаю:

ValueFactory attempted to access the Value property of this instance.

Теперь я мог бы просто не ссылаться на Context.Current.DeploymentType в конструкторе для Provider и просто выполнять ту же работу, что и ENUM, когда она создается снова и снова, но она неэффективна.

Я мог бы создать ENUM отдельно, а затем снова для Context.Current, но это тоже не так.

Мой текущий код:

public Providers AllProviders = Providers.Instance;

Есть ли способ сказать:

public Providers AllProviders {get; don't instantiate me until someone calls me}
Теги:
design-patterns
singleton

1 ответ

1
Лучший ответ

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

В вашем примере свойство инициализируется при построении объекта из-за его объявления. Чтобы избежать его инициализации во время построения объекта, вы можете сделать это:

public Providers AllProviders
{
    get
    {
        if (this.allProviders == null) this.allProviders = Providers.Instance; // alternatively, do what Providers.Instance is actually doing
        return this.allProviders;
    }
}

Похоже, это должно решить эту проблему, если я правильно ее понял. Сделав это изменение, во время строительства свойство не инициализируется, а Providers.Instance не вызывается. Он вызывается (а затем кэшируется) только при доступе к AllProviders.

Разумеется, он не является потокобезопасным (если Providers.Instance не является потокобезопасным), и вам, возможно, придется сделать некоторую работу, чтобы сделать его потокобезопасным, что произойдет с предложенным вами подходом (т.е. "не создавайте экземпляр, пока меня не назовут").

  • 0
    К вашему сведению: вам также может не понадобиться поле this.allProviders, если Providers.Instance уже обрабатывает случай не инициализации, если инициализация уже выполнена. В идеале так и должно быть, но я включил поле this.allProviders, потому что я не знаю, что находится в Providers.Instance.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню