![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Есть такой волшебный паттерн - RAII, и его всякие модификации в языках без автоматического вызова деструкторов(try-finally, using(чего-нибудь IDisposable)) и т.д.
В общем, его применение соответствует тому, что мы создаем/открываем ресурс при входе в блок кода и гарантированно закрываем/разрушаем его при выходе из блока. Причем при любом выходе(в дельфях, например break, continue, exit, выкидывание исключения - все вызывают finally). Но в итоге можно считать, что вход и выход производятся таки вокруг линейного потока выполнения.
А мне нужно такое же, но для ситуации, когда ресурс живет внутри сложного workflow с ожиданием действий от пользователя. Т.е. например - при логине в систему создается некий объект, и при логауте или при закрытии программы - разрушается. Тут еще не так сложно, а вот в случае, когда состояний штук пять, и в двух из них ресурс не нужен, а в трех нужен, а переходы могут быть какие попало - вручную создавать-разрушать и следить за временем жизни ресурса становится занудно.
Вот сижу, думаю, как и чем бы это кошерно описать на c#. Пока ничего толкового в голову не пришло, кроме описания состояний как объектов с полями для каждого нужного ресурса, помеченных специально назначенным атрибутом.
Переход между состояниями это будет хитрая функция, преобразующая объект текущего состояния в объект нового состояния(хотя на самом деле тут есть зло в том, что на самом деле удобнее было бы состояние представить как mix-in из нескольких объектов, и функцию перехода разбить на несколько более простых), перед ее применением будет проверяться не нужно ли разрушить ресурсы из старого состояния, а после применения - не нужно ли создать ресурсов для нового. В большинстве случаев, переход по своей сути и представляет уничтожение старых ресурсов и создание новых, с их инициализацией. Т.е. в функции перехода ничего писать, в общем-то, кроме инициализации ресурсов и не нужно будет - остальное будет выполнено автоматически.
А еще блин обработка ошибок для всего этого - переход между состояниями может не произойти, т.е. нужно будет корректно откатиться назад к старому состоянию, чтобы гуй не оказался в промежуточном.
Кстати, еще во всем этом меня сильно напрягает идея класса, у которого всегда существует не более одного объекта-экземпляра. Чем-то это противоречит смыслу ООП, по моему.
PS: Кстати, в последнее время все идеи "чего не хватает в языках программирования" сводятся к тому, что линейная одномерная структура текста-кода не всегда адекватно соответствует задаче. Например в ней описывать реляционные таблицы - напряжно, в отличие от их естественного вида-гридов. Про графы вообще речи нет, их удобный для восприятия вид - картинка - дико не удобен для редактирования. Что-нибудь еще более сложное из структур, сложнее графов, бывает?:)
В общем, его применение соответствует тому, что мы создаем/открываем ресурс при входе в блок кода и гарантированно закрываем/разрушаем его при выходе из блока. Причем при любом выходе(в дельфях, например break, continue, exit, выкидывание исключения - все вызывают finally). Но в итоге можно считать, что вход и выход производятся таки вокруг линейного потока выполнения.
А мне нужно такое же, но для ситуации, когда ресурс живет внутри сложного workflow с ожиданием действий от пользователя. Т.е. например - при логине в систему создается некий объект, и при логауте или при закрытии программы - разрушается. Тут еще не так сложно, а вот в случае, когда состояний штук пять, и в двух из них ресурс не нужен, а в трех нужен, а переходы могут быть какие попало - вручную создавать-разрушать и следить за временем жизни ресурса становится занудно.
Вот сижу, думаю, как и чем бы это кошерно описать на c#. Пока ничего толкового в голову не пришло, кроме описания состояний как объектов с полями для каждого нужного ресурса, помеченных специально назначенным атрибутом.
Переход между состояниями это будет хитрая функция, преобразующая объект текущего состояния в объект нового состояния(хотя на самом деле тут есть зло в том, что на самом деле удобнее было бы состояние представить как mix-in из нескольких объектов, и функцию перехода разбить на несколько более простых), перед ее применением будет проверяться не нужно ли разрушить ресурсы из старого состояния, а после применения - не нужно ли создать ресурсов для нового. В большинстве случаев, переход по своей сути и представляет уничтожение старых ресурсов и создание новых, с их инициализацией. Т.е. в функции перехода ничего писать, в общем-то, кроме инициализации ресурсов и не нужно будет - остальное будет выполнено автоматически.
А еще блин обработка ошибок для всего этого - переход между состояниями может не произойти, т.е. нужно будет корректно откатиться назад к старому состоянию, чтобы гуй не оказался в промежуточном.
Кстати, еще во всем этом меня сильно напрягает идея класса, у которого всегда существует не более одного объекта-экземпляра. Чем-то это противоречит смыслу ООП, по моему.
PS: Кстати, в последнее время все идеи "чего не хватает в языках программирования" сводятся к тому, что линейная одномерная структура текста-кода не всегда адекватно соответствует задаче. Например в ней описывать реляционные таблицы - напряжно, в отличие от их естественного вида-гридов. Про графы вообще речи нет, их удобный для восприятия вид - картинка - дико не удобен для редактирования. Что-нибудь еще более сложное из структур, сложнее графов, бывает?:)
no subject
Date: 2009-08-30 07:08 pm (UTC)Там есть именно блоки, для циклов, лямбдей и прочей мишуры.
Зачем дублировать работу Garbage Collector'а ? Нет больше ссылок на объект - в сад.
no subject
Date: 2009-08-30 07:18 pm (UTC)no subject
Date: 2009-08-30 07:18 pm (UTC)Для оных вещей строгое управление временем жизни обязательно. А то может оказаться, что, например, мы вышли из состояния где ресурс нужен в состояние где не нужен, забыли его, но сборщик мусора до него еще не добрался, а мы уже зашли в новое состояние, где он опять нужен, но открыть его можно только один раз, и все грохнулось.
В принципе, можно было бы его вообще не закрывать в таком случае, а хранить в каком-то глобальном пуле в течение некоторого времени и активировать повторно при надобности. Но что-то меня повторная активация и глобальные состояния напрягают - я предпочитаю все закрыть и начать с чистого листа в следующий раз, так оно надежнее.
no subject
Date: 2009-08-30 07:27 pm (UTC)Была в чём-то пересекающаяся задача - по прилёту сигнала (SIGHUP) - зачистить кэши и переоткрыть все файлы. В итоге даже не стали возиться с глобальной регистрацией всего и вся, находили все объекты типа кэш с помощью Object#kind_of? и дёргали найденное за сиську с табличкой flush().
Сами кэши хранились как переменные класса и разделялись соотвественно всеми объектами класса.
no subject
Date: 2009-08-30 07:38 pm (UTC)Перебрать поля рефлекшеном, выбрать отмеченные атрибутом "ресурс", грохнуть ненужные, создать новые, инициализировать их.
спасибо)
Date: 2009-08-30 07:12 pm (UTC)извините.
Re: спасибо)
Date: 2009-08-30 07:19 pm (UTC)no subject
Date: 2009-08-30 09:10 pm (UTC)no subject
Date: 2009-08-30 09:11 pm (UTC)Примерно с таким я сталкивался в CL, решение получилось что-то из серии (with-resource (resource) (with-call/cc ...))
Без call/cc я честно говоря хз чем эмулировать развесистый workflow в линейном виде. Я не вижу как тут можно подсунуть raii, видимо, надо какое-то другое решение искать.
no subject
Date: 2009-08-30 10:04 pm (UTC)Далее это можно один-в-один перенести в C#.
no subject
Date: 2009-08-30 10:30 pm (UTC)т.е. объект подписывается на события которые его интересуют и при наступлении определенного события выполняет необходимые действия.
емнип на с# это через делегаты реализуется обычно.
no subject
Date: 2009-08-31 12:30 am (UTC)no subject
Date: 2009-08-31 02:08 am (UTC)no subject
Date: 2009-08-31 02:43 am (UTC)В таких ситуациях создаются холдеры - т.е. классы или объекты, или что там ещё, единственная цель которых - захватить ресурс, и освободить его при освобождении холдера.
Таким образом, мы опциональные объекты храним в коллекции холдеров, а коллекции прибиваем гвоздями к объекту, отвечающему за сессию, и который при этом есть всегда - в твоём примере это объект "сессия после логина".