2012-05-30 3 views
0

Каков наилучший способ инициализации статических полей с помощью статического метода init и после этого убедитесь, что метод никогда не вызывается снова? (не более одного раза в течение срока действия программы)Статический шаблон инициализации

Это пример того, что я сейчас думал о том, что мне кажется очень простым, но я не мог найти примеров подобных шаблонов, которые касаются этого:

class Entity 
{ 
    static Manager manager; 
    static bool isInitialized; 

    public static void Initialize(Manager manager) 
    { 
     if (isInitialized) 
      throw Exception("Class Entity already initialized." 
       + "Do not call Entity.Initialize() twice."); 
     isInitialized = true; 
     Entity.manager = manager; 

    } 
} 
+1

Является ли «менеджер» одноэлементно? Я думаю, вам лучше смотреть в контейнеры IoC для этого. – n8wrl

+0

Вы можете найти интересующий нас класс «Lazy ». – Servy

+0

Просто хочу обратить ваше внимание на то, что Singletons могут вводить зависимости и хрупкость в ваших приложениях - [здесь хороший блог] (http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global -state-singletons /), чтобы помочь объяснить и избежать. Как указано в @ n8wrl, посмотрите на использование инъекции зависимостей. – RobertMS

ответ

6

что является лучшим способом для инициализации статических полей с помощью статического метода инициализации, а затем убедитесь, что метод никогда не вызывается снова?

Действительно ли у вас есть для этого? Почему вы не хотите создавать экземпляр Manager и сделать его доступным для кода, который опирается на него посредством инъекции зависимостей? Это сделает ваш код намного чище:

  • Вы бы позволить ему быть проверяемым с различными путями инициализации
  • Вам не нужны будет любая проверка «плохой» дубликат инициализации
  • Вам не нужен будет для структурирования вашего кода вызова для указания единственной точки инициализации для этого класса. (Вы, возможно, потребуется сделать что-то подобное для IoC контейнера, конечно ...)
  • Вы хотите разрешить ваш код, который зависит от того, чтобы быть более проверяемым слишком
  • код, который зависит от Manager бы выразить эту зависимость более ясным образом

Я подозреваю, что вы не нашли подобных примеров, потому что это анти-шаблон.

Если вы сделать идти за текущий подход, вы действительно должны попытаться сделать его поточно-тоже ...

+0

Существует один экземпляр 'Manager', созданный при запуске программы, и это один из жизненно важных классов программы. Однако экземпляры 'Entity', вероятно, не будут созданы, пока не пройдет какое-то время. – Acidic

+0

@Acidic: Так звучит, как «Менеджер» - это зависимость, которую нужно вводить в различные другие биты вашей программы. Я отредактирую свое сообщение, чтобы это отразить, но это не меняет фундаментальной точки: заставляя эту инициализацию быть статичной, вы делаете свой код более сложным для тестирования, а зависимости сложнее обнаружить. –

+0

В этом случае 'Диспетчер' никогда не будет использоваться в статической области. Я просто пытаюсь представить его как защищенное свойство для подклассов. Там потенциально могут быть десятки тысяч экземпляров подкласса «Entity», и таким образом я мог бы сэкономить пространство, которое каждый из них занимал бы, имея собственные ссылки на потенциальные зависимости. Это также не помешало бы конструктору. – Acidic

1

Не более думаю, что, если эта схема работает для вас, идти с Это. Не всегда есть «правильный» ответ, и попытка придерживаться жестких моделей и практик только ради того, чтобы придерживаться их тоже не является хорошей идеей. ИМХО.

+0

Я склонен согласиться, но я, если найду другие примеры и узнаю из этого, я бы поприветствовал его. – Acidic

+0

В этом случае есть множество причин придерживаться хороших практик, причем первичным является проверяемость. Это не «только ради того, чтобы придерживаться их». –

+0

@JonSkeet Конечно, но я думаю, что многие люди (включая меня) склонны немного думать о вещах и пытаются реализовать «правильный» узор, когда иногда что-то простое, как то, что у него есть, будет работать нормально. – CodingGorilla

1

Извините за то, что вы указали очевидное, но вы можете использовать инициализатор объекта или статический конструктор. Кроме того, вы можете просто не вызывать метод. Шутки в сторону. Почему кто-то вызовет метод, называемый , в любом случае, инициализирует.

Что вы можете сделать, это this. Вы можете скрыть метод от IntelliSense и аналогичный с этим атрибутом. Остановляет это от загромождения выпадающего списка

+0

Статический конструктор здесь не помогает - есть параметр. –

+0

О, ты прав. Виноват. Тогда я добавлю что-то полезное. – GregRos

+0

О, вау, этот атрибут потрясающий. – Acidic

0

Ваша реализация не является потокобезопасной, но в остальном разумной. Если он предназначен для использования в многопоточной среде, добавьте блокировку.

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

+0

Я не включил потокобезопасную реализацию, просто чтобы сохранить код коротким. Во всяком случае, существует только один экземпляр «Диспетчера», поэтому единственный способ, которым он может быть * разрушен, - это если «null» передан, но я считаю «особым случаем», поэтому я оставил его в этом примере. – Acidic

0

Не можете ли вы использовать статический конструктор?

Конечно, у вас нет контроля над тем, когда этот конструктор вызван, но не знаю, является ли это требованием.

http://msdn.microsoft.com/en-us/library/k9x6w0hc(v=vs.80).aspx

+1

Это была моя первая мысль - тогда я увидел параметр ... –

+0

Ага действительно. Пропущен параметр. –

+0

Этот параметр получил меня тоже. – GregRos

0

Вы можете использовать одноплодный шаблон с параметрами только выставить определенную функциональность переменной Manager.

class Entity 
{ 
    private Manager _manager = null; 

    public Manager manager 
    { 
     get 
     { 
      return _manager; 
     } 
     set 
     { 
      if (manager == null) 
      { 
       _manager = value; 
      } 
     } 
    } 
    /* rest of class */ 
} 

Теперь вы можете использовать объект-менеджер как любую переменную, но повторные наборы не изменят значение.

this.manager = new Manager(0); // sets the manager 
this.manager = new Manager(1); // does nothing 

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

this._manager = null; 
+0

Экземпляр «Менеджера», который я планирую передать методу «Инициализация», скорее всего, будет создан задолго до того, как метод фактически будет вызван. Я также не хочу, чтобы поле было общедоступным, просто видимым внутри 'Entity' и потенциально в наследующих типах. Я не думаю, что шаблон Singleton подходит для этого случая. – Acidic

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