Поругайте... Делегат вместо if
От: /Forester/ Россия http://www.akteam.ru
Дата: 17.06.13 15:38
Оценка:
Всем привет!

Есть singleton, но с двухстадийным созданием. Типа такого:

class TwoPhaseSingleton
{
  static s_instance = new TwoPhaseSingleton();
  public static Instance { get { return s_instance; } }
  private TwoPhaseSingleton()
  {
  }

  public void Init() { ... }
}

// где-то на старте приложения...
TwoPhaseSingleton.Instance.Init();


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

Вторая фаза создания объекта может быть повторена через некоторое время и может пройти успешно.

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

  ...
  public static Instance 
  { 
    get 
    { 
      if(!s_instance.Initialized)
      {
        s_instance.Init();
      }
      return s_instance; 
    } 
  }
  ...


Но диспетчеризацию по if'ам не люблю. Мне более симпатичен такой вариант:

class TwoPhaseSingleton
{
  static s_instance = new TwoPhaseSingleton();
  public static Instance 
  { 
    get 
    { 
      s_instance.Init();
      return s_instance; 
    } 
  }
  private TwoPhaseSingleton()
  {
    Init = InitReal;
  }

  public Action Init { get; private set; }

  private void InitReal() { ...; Init = InitFake; }
  private void InitFake() { }
}


То есть Init — это не метод, а делегат. До инициализации в Init лежит функция, которая действительно выполняет инициализацию. После успешной инициализации в Init заносится пустая функция, которая ничего не делает.

Поругайте, сравните оба эти варианта. Какие есть плюсы и минусы?
Первый вариант очевиднее и понятнее для ООП. Второй ближе к ФП.
В первом варианте меньше расход памяти.
А что со скоростью выполнения?
Re: Поругайте... Делегат вместо if
От: hardcase Пират http://nemerle.org
Дата: 17.06.13 16:02
Оценка:
Здравствуйте, /Forester/, Вы писали:

F>А что со скоростью выполнения?


if однозначно быстрее и проще для чтения. Кстати, не видно защиты от многопоточной инициализации.
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Поругайте... Делегат вместо if
От: Tom Россия http://www.RSDN.ru
Дата: 17.06.13 16:45
Оценка: +4 :)))
F>Есть singleton,
Охххх

F>но с двухстадийным созданием. Типа такого:

Синглетон этот не нужен тебе
Народная мудрось
всем все никому ничего(с).
Re: InitFake не нужен
От: igor-booch Россия  
Дата: 17.06.13 17:25
Оценка:
Вместо

private void InitReal() { ...; Init = InitFake; }


можно написать


private void InitReal() { ...; Init = () => {}; }
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Re[2]: Поругайте... Делегат вместо if
От: /Forester/ Россия http://www.akteam.ru
Дата: 17.06.13 19:13
Оценка:
Здравствуйте, hardcase, Вы писали:

F>>А что со скоростью выполнения?


H>if однозначно быстрее и проще для чтения. Кстати, не видно защиты от многопоточной инициализации.


Мне тоже кажется, что if быстрее. Но что-то я на ФП подсел...
Потокобезопасность не стал включать в примеры, вопрос не в ней.
Re[2]: InitFake не нужен
От: /Forester/ Россия http://www.akteam.ru
Дата: 17.06.13 19:15
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>Вместо


IB>
IB>private void InitReal() { ...; Init = InitFake; }
IB>


IB>можно написать



IB>
IB>private void InitReal() { ...; Init = () => {}; }
IB>


Спасибо! Действительно, так может быть лучше.
Re[2]: Поругайте... Делегат вместо if
От: /Forester/ Россия http://www.akteam.ru
Дата: 17.06.13 19:17
Оценка:
Здравствуйте, Tom, Вы писали:

F>>Есть singleton,

Tom>Охххх

F>>но с двухстадийным созданием. Типа такого:

Tom>Синглетон этот не нужен тебе

Мне он удобен
Re[3]: Поругайте... Делегат вместо if
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.06.13 19:24
Оценка:
Здравствуйте, /Forester/, Вы писали:

F>Мне тоже кажется, что if быстрее. Но что-то я на ФП подсел...

А причем тут ФП?
Re[4]: Поругайте... Делегат вместо if
От: /Forester/ Россия http://www.akteam.ru
Дата: 17.06.13 19:45
Оценка:
Здравствуйте, samius, Вы писали:

F>>Мне тоже кажется, что if быстрее. Но что-то я на ФП подсел...

S>А причем тут ФП?

То, что функцией оперирую
Согласен, до ФП тут далеко...
Re[3]: Поругайте... Делегат вместо if
От: Sinix  
Дата: 18.06.13 05:06
Оценка: +1
Здравствуйте, /Forester/, Вы писали:

F>Потокобезопасность не стал включать в примеры, вопрос не в ней.


Ну... тогда определяйтесь, что для вас сейчас важно в первую очередь. Если код экспериментальный, на предмет поиграться — пишите как вам удобно.

Если код пойдёт в продакшн — нужно нафиг выбросить "мне нравится" и сосредоточиться на исходной проблеме:
1. Заводим глобальное состояние, но с глюком который может порушить нафиг весь процесс.
2. Вместо того, чтобы поправить — находим костыль (повторяем вызов — вдруг в этот раз сработает?).
3. Использовать костыль один раз лень — поэтому ищем способ протащить костыль (возможно, с побочными эффектами) во все места приложения, чтоб наверняка сработало.

Вам не кажется, что проблема у нас — не в выборе способа протащить костыль, а немного выше?

P.S. Сами просили поругать
Re[3]: Поругайте... Делегат вместо if
От: dilmah США  
Дата: 18.06.13 05:18
Оценка: +3 :))
F>Мне тоже кажется, что if быстрее. Но что-то я на ФП подсел...

Re[4]: Поругайте... Делегат вместо if
От: /Forester/ Россия http://www.akteam.ru
Дата: 18.06.13 05:55
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Ну... тогда определяйтесь, что для вас сейчас важно в первую очередь. Если код экспериментальный, на предмет поиграться — пишите как вам удобно.


S>Если код пойдёт в продакшн — нужно нафиг выбросить "мне нравится" и сосредоточиться на исходной проблеме:

S>1. Заводим глобальное состояние, но с глюком который может порушить нафиг весь процесс.
S>2. Вместо того, чтобы поправить — находим костыль (повторяем вызов — вдруг в этот раз сработает?).
S>3. Использовать костыль один раз лень — поэтому ищем способ протащить костыль (возможно, с побочными эффектами) во все места приложения, чтоб наверняка сработало.

S>Вам не кажется, что проблема у нас — не в выборе способа протащить костыль, а немного выше?


Конечно, проблема выше. Периодически БД недоступна. Но с этим я ничего сделать не могу, к управлению СУБД доступа не имею. Поэтому кроме повторных попыток подключения ничего не остается.
Можно назвать это костылем, а можно восстановлением после сбоя

Меня интересовал вопрос избавления от if'ов. Когда поведение объекта зависит от его состояния, как бы так не делать диспетчеризацию на if'ах. Вариант с таблицами по типу конечного автомата для двух состояний излишне сложен. Шаблон стратегия хорошо подходит под задачу, но требует две дополнительные сущности. Поэтому попробовал вариант с подменой метода, но отказался от него и остался с if'ам.
Re[5]: Поругайте... Делегат вместо if
От: Sinix  
Дата: 18.06.13 06:33
Оценка:
Здравствуйте, /Forester/, Вы писали:

F>Конечно, проблема выше. Периодически БД недоступна. Но с этим я ничего сделать не могу, к управлению СУБД доступа не имею. Поэтому кроме повторных попыток подключения ничего не остается.


О, пошла конкретика

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

Если речь идёт о стандартном DbConnection (или его наследнике) — или не храните его вообще, или храните в закрытом состоянии, фреймворк уже позаботился о пуле соединений за вас. Всю логику по получению открытого и валидного соединения спрячьте в отдельный метод. Вот тогда уже можно будет смотреть, что удобнее — простой if, или чехарда с подменой делегатов.


F>Меня интересовал вопрос избавления от if'ов. Когда поведение объекта зависит от его состояния, как бы так не делать диспетчеризацию на if'ах.


В фреймворке есть (как минимум) два места, где используется похожий подход

Посмотрите в ilspy на реализацию System.Transactions.Transaction. У него есть поле — TransactionState. Это абстрактный класс в который вынесена логика, зависящая от состояния транзакции. У класса есть наследники — ActiveStates, TransactionStateEnded и т.д. Само изменение состояния транзакции (упрощённо) заключается в замене содержимого поля на нужного наследника.

Тот же подход реализован в Lazy<T> — одно поле m_boxed, в котором лежит или готовое значение, или ссылка на фабрику.

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

Один вопрос — нафига оно здесь надо? Без обид, такое очучение, что вы пытаетесь натянуть задачу сразу на два паттерна (синглтон и стратегия), при этом ни саму задачу, ни паттерны особо и не жалеете
Re: Поругайте... Делегат вместо if
От: Ilinichev  
Дата: 18.06.13 06:35
Оценка:
Здравствуйте, /Forester/, Вы писали:

F>То есть Init — это не метод, а делегат. До инициализации в Init лежит функция, которая действительно выполняет инициализацию. После успешной инициализации в Init заносится пустая функция, которая ничего не делает.


Нифига непонятен огород. А каким образом, собственно, реконект производится? Где Init = InitReal? Только в конструкторе? А смысл?
Re[6]: Поругайте... Делегат вместо if
От: /Forester/ Россия http://www.akteam.ru
Дата: 18.06.13 08:07
Оценка:
Здравствуйте, Sinix, Вы писали:

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


Да нормально все с синглтоном, что вы все до него докопались

S>В фреймворке есть (как минимум) два места, где используется похожий подход


S>Посмотрите в ilspy на реализацию System.Transactions.Transaction. У него есть поле — TransactionState. Это абстрактный класс в который вынесена логика, зависящая от состояния транзакции. У класса есть наследники — ActiveStates, TransactionStateEnded и т.д. Само изменение состояния транзакции (упрощённо) заключается в замене содержимого поля на нужного наследника.


Про это писал в предыдущем сообщении — шаблон стратегия. Здесь он излишен.

S>Ни в одном из вариантов делегаты не используются и логика инициализации не перемешана с самой подменой делегатов.

То, что не используются — это не показатель. И потом, не используются явно. Неявно же в шаблоне стратегии происходит подмена методов через замену виртуальных таблиц.

S>Первое — потому что делегаты недостаточно четко документируют намерения, нужно извращаться чтобы понять какое состояние представляет текущий делегат.

Нормально они документируют. Ничем не хуже чем, например, через enum состояния описывать. Все тоже самое получается.
Другое дело, что такой способ непривычен. Так это вопрос времени и опыта.
А вот отлаживаться совсем не просто. Но это вопрос к инструменту отладки, а не к способу подмены делегата.
S>Второе — банальное разделение ответственности, "я не даю кредитов — они не торгуют семечками"(с).
А этот тут причем? Типа делегат для другого предназначен?

S>Один вопрос — нафига оно здесь надо? Без обид, такое очучение, что вы пытаетесь натянуть задачу сразу на два паттерна (синглтон и стратегия), при этом ни саму задачу, ни паттерны особо и не жалеете


Какие обиды... Фиг знает, может и так. За паттерны никогда особо не переживал.
Re[3]: Поругайте... Делегат вместо if
От: IB Австрия http://rsdn.ru
Дата: 18.06.13 08:51
Оценка:
Здравствуйте, /Forester/, Вы писали:

F>Мне он удобен



FAQ «Как сварить яйцо в микроволновке?»




Q: Сколько времени надо варить куриное яйцо в микроволновке? Микроволновка «Bosch».
A: Яйца нельзя варить в микроволновке, потому что они взрываются. Используйте кастрюлю и обычную плиту.




Q: Как надо обработать яйцо, чтобы сварить его в микроволновке?
A: Не существует способа сварить яйцо в микроволновке.




Q: Как именно происходит взрыв яйца с точки зрения науки и почему?
A: Яйцо резко теряет целостность и приобретает форму стенок печки. Это происходит из-за нагревания в печах микроволнового типа. Кулинарная наука запрещает это делать.




Q: Я налила в стеклянную кастрюлю воды, чтобы уравнять осмотическое давление, положила два яйца, накрыла тарелкой и поставила в печку. Вода еще не закипела, а яйца уже взорвались и разбили тарелку!
A: Вы забыли посолить воду. Кастрюля должна быть металлической, печка — обычная, не микроволнового типа.




Q: Я сварил яйцо отдельно вкрутую, а затем поставил разогреть на 20 секунд. Оно взорвалось. В чем моя ошибка?
A: Не следовало разогревать яйцо. Вы могли съесть его холодным или разогреть, опустив в горячую воду на 2-5 минут.




Q: Как при помощи микроволновки познакомиться с мужчиной? Мне 27 лет, рыба.
A: Не следует готовить яйца в микроволновке, сходите на вечеринку или дискотеку.




Q: Цитирую инструкцию к «Samsung»: «Яйцо в микроволновке не сварится, а испечется. Для этого следует разбить скорлупу яйца, проследив, чтобы пленка под скорлупой также была повреждена.»
A: Испеченное в микроволновке яйцо имеет ряд недостатков: пропечено неравномерно, мелкая скорлупа хрустит на зубах, трудно собирать куски со стенок. Повреждать скорлупу раньше времени не имеет смысла — вы можете испачкать руки.




Q: У меня постоянно сбиваются часы в микроволновке. Что посоветуете?
A: Не следует варить яйцо в микроволновке. Часы сбиваются самопроизвольно в большинстве моделей, с приготовлением яиц это не связано.




Q: Как так получилось в природе, что взрываются именно яйца?
A: Чтобы этого избежать, не кладите их в микроволновку.




Q: Я безумно, безумно мечтаю хоть раз испечь яйцо в микроволновке!
A: Испеките курицу — фактически это бывшее яйцо.




Q: Я обмотал яйцо скотчем, чтобы оно не взорвалось, но оно все равно взорвалось, испачкало стенки содержимым и кусками скотча.
A: Протрите микроволновку влажной тряпкой. Присохшие куски скотча ототрите содой. Не следует тереть стенки металлической мочалкой и скоблить ножом.




Q: Я сварил вкрутую три перепелиных яйца, очистил от скорлупы, положил в булку для гамбургеров и разогрел в микроволновке. Они взорвались и разорвали булку.
A: Яйца следовало есть вприкуску, не разогревая вместе с булкой.




Q: Свекровь постоянно твердит, что в микроволновке нельзя варить яйца.
A: Да.




Q: Только ли куриные яйца взрываются в микроволновке?
A: Все птичьи яйца взрываются в микроволновке. На продуктовых рынках и мясных базах можно купить бычьи или бараньи яйца, лишенные этого недостатка. Но вкуснее варить куриные на огне или с помощью кипятильника.




Q: Я проколол в яйце дырку, выпил его, а пустую скорлупу стал греть в микроволновке. Она пахла гарью, а затем лопнула.
A: Вам следовало хранить пустую скорлупу, избегая ее нагревания в микроволновке.




Q: Где в Таганроге можно купить хорошую микроволновку дешево? Какую модель посоветуете? СВЧ и микроволновка — это одно и то же?
A: Это одно и то же. Купив микроволновку, не следует готовить в ней яйца.




Q: Спичкой я пробил с боков яйца две дырочки для выравнивания давления, поставил его в микроволновку, но оно взорвалось.
A: Вымойте стенки микроволновки влажной тряпкой.




Q: Я варил яйцо в микроволновке 10 секунд и оно не взорвалось. На вкус показалось сырым.
A: Используйте микроволновку большей мощности — от 900 ватт и выше, либо увеличьте время приготовления.




Q: Я поджарил яичницу, а затем разогрел ее в микроволновке — она не взорвалась!
A: Яичницы и омлеты, в отличие от яиц, редко взрываются в микроволновках.




Q: Я знаю как минимум трех людей, которые варили яйца в микроволновке и ничего плохого не случилось!
A: Нет ничего плохого в том, чтобы лишний раз вымыть микроволновку.




Q: У меня нет микроволновки, есть плита. Можно ли положить яйцо на нижнюю решетку в духовке?
A: Микроволновка удобна своей быстротой. Вам придется ожидать взрыва в духовке 10-20 минут.




Q: Могу я положить яйцо в кастрюлю с водой и сварить в газовой духовке?
A: Да, но это вариант средний. Гораздо лучше поставить кастрюлю на конфорку, гораздо хуже — в микроволновку.




Q: Просто интересно, каково количество яиц, взорванных во всем мире со дня изобретения микроволновок?
A: Чем меньше, тем лучше.




Q: Микроволновка — творение Диавола! СВЧ — означает Служу Воинству Черта! Читайте Библию! Они взрываются потому, что сам Господь не дает варить в микроволновке яйца на Пасху!
A: Будьте благоразумны и в остальное время года.




Q: Если убавить мощность микроволновки до минимума и варить яйцо медленно, в течение нескольких часов, с перерывами?
A: Мощность установите максимальную. Три небольшие картофелины вымойте под краном и положите в микроволновку на 3-7 минут. Ешьте с маслом и солью при помощи чайной ложки.




Q: У меня микроволновка с грилем, это что-то меняет?
A: Ее возможности более широкие. Но в плане яиц она как обычная.




Q: Где можно получить более полную информацию? Есть ли специальная литература о приготовлении яиц в микроволновке?
A: Мы всегда готовы ответить на любые вопросы о том, можно ли варить яйца в микроволновке.




Q: Я поставил яйцо в микроволновку, но оно не взорвалось и не нагрелось.
A: Проверьте, включен ли шнур питания микроволновки в электрическую сеть.




Q: Я сварил яйцо в микроволновке, и оно не взорвалось.
A: Нет.




Q: Какие продукты взрываются в микроволновке так же, как и яйца?
A: Так зрелищно, как яйца, не взрываются никакие продукты.




Q: Мне рассказывали, что есть специальная насадка к микроволновке для варки яиц.
A: Речь шла о машинке для нарезки крутых яиц. Магазин имеет право продавать ее или просто давать в рекламных целях вместе с микроволновкой и другой кухонной техникой. Не забудьте очистить яйцо от скорлупы.




Q: Следуя вашему FAQ «Как варить яйцо в микроволновке», я стал его варить, но оно взорвалось и сильно испачкало мне аппарат!
A: Вы должны были внимательно дочитать FAQ до конца, не прерывая чтение после названия.




--------------------------------------------------------------------------------


PS: Согласно последним данным, все-таки есть устройство для варки яиц в микроволновке! Это некий сфероид, нижняя часть которого наполненяется водой для кипения, а верхняя хитро экранирована металлом (почему металл не плавится — загадка). Там и находятся закрытые от излучения яйца, которые варятся за счет горячего пара, поднимающегося снизу. Варятся они минут 15 на максимальной мощности, так что толку от устройства не много, и кайф, прямо скажем, бычий. И, кстати, нелишне было бы добавить к вышесказанному, что яйца в микроволновке варить нельзя.

Мы уже победили, просто это еще не так заметно...
Re[7]: Поругайте... Делегат вместо if
От: Sinix  
Дата: 18.06.13 08:55
Оценка:
Здравствуйте, /Forester/, Вы писали:

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

F>Да нормально все с синглтоном, что вы все до него докопались
Потому что нефиг спорить о выборе резины для шин, если колесо квадратное

F>Про это писал в предыдущем сообщении — шаблон стратегия. Здесь он излишен.

Именно. Тут даже готовое решение будет оверкиллом.

F>Другое дело, что такой способ непривычен. Так это вопрос времени и опыта.

Скорее, соотношения "затраты-полезный выхлоп". Если судить по примеру выше — напоминает переизобретение паровоза на конной тяге.
Вполне возможно, в реальном коде этот вариант на порядок удобней альтернативы — очевидно, надо использовать его и не дёргаться *(разумеется, сопроводив комментариями). Если не удобней — проще прибить чем мучаться с поддержкой.

S>>Второе — банальное разделение ответственности, "я не даю кредитов — они не торгуют семечками"(с).

F>А этот тут причем? Типа делегат для другого предназначен?
Неа, в примерах что я приводил мухи (пользовательская логика) и котлеты (инфраструктурный код) явно разделены. Если ограничиться только практической стороной вопроса — это позволяет при необходимости вытащить логику инициализации в переиспользуемый класс (собственно, в Lazy это уже сделано) и не копипастить всё решение вместе с мухами целиком.

Если лезть в теорию, то чем больше ответственностей несёт отдельно взятый метод — тем больше он заточен под одно конкретное понимание проблемы. Несмертельно, но неприятно, особенно если проблема (или её понимание) имеют свойство меняться.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.