Еще раз об анонимных делегатах и о Java-анонимных классах
Вообще, мне тоже кажется java-вариант читабельнее
в первом варианте я не вижу интерфейса. во втором он просматривается.
это вопрос был или что?1. да, хотелось услышать комментарии по поводу различных вариантов (может еще какие есть интересные).
2. Вы согласны, что джава-анонимные классы были бы весьма полезны в сишарпе (особенное с полным замыканием, как анонимные делегаты)?
3. Может кто даст ссылку, где описывается, почему в сишарпе этого нет.
ConsumeLicense(new ConsumeLicenseProxy;
ConsumeLicense(new ConsumeLicenseProxy(x => ..., ..., ...;
ConsumeLicense(new ConsumeLicenseProxy{SuccessLicenseAction = x => ...});
2) Да, но особой необходимости я пока не увидел.
ConsumeLicense(new ConsumeLicenseProxy;да, это решение в лоб, как еще на Паскале учили, если много параметров у функции, заводим структурку. Но как-то искусственно слишком это в нашем случае, там интерфейс напрашивается, а не структурка из функций.
ConsumeLicense(new ConsumeLicenseProxy(x => ..., ..., ...;
ConsumeLicense(new ConsumeLicenseProxy{SuccessLicenseAction = x => ...});
Если все инициализировать через параметры конструктора, то надо следить за порядком аргументов, не очень удобно. Если инициализировать через свойства (новый синтаксис как он там называется то возможна передача объекта с не инициализированным свойством.
Да и у меня пока C# 2.0
При работе с какими нибудь стандартными бибилиотеками в java есть необходимость использовать анонимные классы с переопределением 2 и более методов?
При работе с какими нибудь стандартными бибилиотеками в java есть необходимость использовать анонимные классы с переопределением 2 и более методов?Есть, но достаточно редко. Например, если со SWING/AWT работать, то бывает.
Интерфейс никуда не делся, и реализуется посредством класса, только не анонимного.
Интерфейс никуда не делсяно тогда есть и интерфейс IConsumeLicenseProxy и класс ConsumeLicenseProxy, т.е. это немного более многословно. В общем, есть несколько вариантов, с мелкими недостатками..., а совсем хорошего нет
1. Если есть свободная лицензия, выдать ее и разрешить показ сайта. Если срок лицензии истекает менее, чем через 30 дней, выдать предупреждение об этом.непонятно, почему ты считаешь, что это надо делать интерфейсом.
2. Если нет свободной лицензии, выдать сообщение “Все лицензии заняты”
3. Если licensing server недоступен, написать что-то типа “Сервис недоступен”
в моем понимании это события(сообщения и пользователь фасада может подписываться на эти события(сообщения а может и не подписываться, может подписываться только на часть из них.
ps
колбаки, имхо, вообще зло, т.к. при использовании колбаков очень тяжело потом на уровне архитектуры понять, что и в какой момент происходит
в моем понимании это события(сообщения и пользователь фасада может подписываться на эти события(сообщения а может и не подписываться, может подписываться только на часть из них.в принципе разумно звучит. Тогда ConsumeLicense надо оформлять как отдельный класс? У LicenseFacade есть еще подобные методы, их тоже оформлять через классы?
колбаки, имхо, вообще зло, т.к. при использовании колбаков очень тяжело потом на уровне архитектуры понять, что и в какой момент происходит
напишите самый правильный вариант
напишите самый правильный вариантможет я чего то не понимаю, но чем плохо это:
если сервер недоступен - RMI прокся кидает ексепшен
если лицензии кончились - серверный код кидает ексепшен
если все ок - то ничего не кидает
оборачиваешь вызов прокси в трай кэтч и вперед
если лицензии кончились - серверный код кидает ексепшенОкончание количества лицензий - это не ошибка, а нормальная ситуация. Мне кажется, что разделять ответы от сервера лицензий через исключения - это не очень правильный подход.
Думаю, что достаточно удобно и расширяемо можно сделать, если запрос к серверу лицензии будет возвращать ответ. А потом этот ответ будет разруливаться клиентом. Ответ надо сделать базовым классом и от него наследовать все конкретные варианты. Самое красивое решение в любом случае можно выбрать только тогда, когда видишь и понимаешь всю задачу в целом. Но я больше склоняюсь к реализации интерфейса, чем к событиям, т.е. предлагаю Java стиль перенести на C#.
Имхо, эксепшены уж точно не лучше колбеков.
RMI
удаленные вызовы делает только LicenseFacade, между фасадом и презентейшен лаером удаленных вызовов нет
Окончание количества лицензий - это не ошибка, а нормальная ситуация. Мне кажется, что разделять ответы от сервера лицензий через исключения - это не очень правильный подход.Возможно. Мне вот кажется, что нормальная ситуация - это когда пользователя пускают внутрь. Все остальное - исключительная ситуация.
т.е. у тебя уже сейчас два типа эксепшена.Ну есть конечно некоторые drawback'и.
Имхо, эксепшены уж точно не лучше колбеков.
Типа как сказал Майк кидания ексепшенов для управления контрол-флоу. Ибо это есть медленно.
В твоем же конкретном случае никакого криминала не вижу. Можно унаследовать оба эксепшена от одного, и потом написать единую обработку всевозможных ошибок.
Если приведешь еще какие то поинты почему эксепшены не нравятся, можно будет поговорить об этом )
это я понимаю =)RMIудаленные вызовы делает только LicenseFacade, между фасадом и презентейшен лаером удаленных вызовов нет
не понимаю что в сокращении RMI то не понравилось?
Если приведешь еще какие то поинты почему эксепшены не нравятся, можно будет поговорить об этом )У тебя нет гарантии, что где-то кто-то не будет ловить эти исключения. Если функция кидает 2-3 типа исключений, а кто-то поймает их в catch(Exception e)? Фактически, ты предлагаешь заводить новое исключение на каждый новый тип ответа от сервера лицензий:
switch (answer) {
case 1: throw new ConnectionOkException;
case 2: throw new LicenseLimitException;
case 3: throw new ConnectionError;
case 4:...
}
...
try {
provider.getLicense;
}
catch (ConnectionOkException e) {
}
...
У тебя нет гарантии, что где-то кто-то не будет ловить эти исключения.У меня вообще нет никаких гарантий.
Если функция кидает 2-3 типа исключений, а кто-то поймает их в catch(Exception e)?
Пусть ловит, ради бога. Одно из предназначений эксепшенов и заключается в выносе кода обработки ошибок в одно место и его унификации.
Фактически, ты предлагаешь заводить новое исключение на каждый новый тип ответа от сервера лицензийДа. А у вас будет правиться интерфейс и в обязательном порядке правиться все реализации.
switch (answer) {А ты подними throw'ы в те места кода, где переменной answer значение присваивается, а саму переменную выкинь.
case 1: throw new ConnectionOkException;
case 2: throw new LicenseLimitException;
case 3: throw new ConnectionError;
case 4:...
}
Пусть ловит, ради бога. Одно из предназначений эксепшенов и заключается в выносе кода обработки ошибок в одно место и его унификации.А если надо разделить два-три успешных ответа? Ошибка - это ошибка; отсутствие связи с сервером может быть исключительной ситуацией. Но это уж точно надо отделять от окончания количества лицензий.
Да. А у вас будет правиться интерфейс и в обязательном порядке правиться все реализации.Да, а у тебя либо нарушится Java-style, т.е. везде throws BaseException, либо ты напишешь все исключения по очереди в throws. Да ещё если кто-то это исключение перехватит и за тебя обработает, то программа перестанет работать. Решение с исключениями никак не расширяется. Я согласен, что должно быть дерево классов для ответов от сервера, но разруливать его надо по-другому.
А ты подними throw'ы в те места кода, где переменной answer значение присваивается, а саму переменную выкинь.
Это был пример той архитектуры, которую ты предлагаешь. Она именно так и устроена, просто answer приходит со стороны сервера лицензий.
А если надо разделить два-три успешных ответа? Ошибка - это ошибка; отсутствие связи с сервером может быть исключительной ситуацией. Но это уж точно надо отделять от окончания количества лицензий.Если нужно разделить два-три успешных ответа - то конечно нет. Там либо разбить на несколько методов если получится, либо возвращать объект и его процессить, либо колбеки.
Ваши колбеки, кстати, это почти паттерн Builder, со всеми его плюсами и недостатками.
Да, а у тебя либо нарушится Java-style, т.е. везде throws BaseException, либо ты напишешь все исключения по очереди в throws.Если BaseException'ы у разных групп кода разные, то опять же не вижу ничего криминального. Криминал - если везде throws Exception и catch(Exception). Это очевидный мизюз, да.
А так, вон все живут со, скажем, SQLException, и все окей. (есть конечно кейсы, когда от конкретной бд хотят зависеть)
Да ещё если кто-то это исключение перехватит и за тебя обработает, то программа перестанет работать. Решение с исключениями никак не расширяется.Такие вещи ложатся достаточно высоко по стеку, так, чтобы перехватывать было некому.
Ваше решение в перспективе тоже может плохо расширяться.
У вас coupling между кодом license сервера и кодом приложения больше, чем в случае с ексепшенами.
Это был пример той архитектуры, которую ты предлагаешь. Она именно так и устроена, просто answer приходит со стороны сервера лицензий.А кто сказал что со стороны сервера лицензий приходит ансвер? Сервер лицензий сериализует тот ексепшен, что был выкинут проксируемым методом и отдает его клиентской проксе. Никаких ансверов.
в идеале - да. все является объектами.
но в реальности, на данной задаче - это скорее метод который возвращает результат (сообщение).
как лучше оформить результат метода: как enum, строку или миникласс можно уже подумать:
1. enum - если важна скорость
2. строка - если важна расширяемость
3. миникласс - если важно удобство
имхо, в данном случае лучше выбрать третье с оформлением класса как enum:
class ConsumeLicenseResult
{
public static readonly ConsumeLicenseResult Ok = new ...;
public static readonly ConsumeLicenseResult OkButWarning = new ...;
public static readonly ConsumeLicenseResult NoFreeLicense = new ...
public static readonly ConsumeLicenseResult NoConnectionToServer = new ...
}
Если нужно разделить два-три успешных ответа - то конечно нет.Но ты в своей архитектуре сразу закладываешься на невозможность выполнения этого действия. Практика показывает, что это заканчивается рефакторингом.
Ваши колбеки, кстати, это почти паттерн Builder, со всеми его плюсами и недостатками.Ну я предлагаю не совсем колбэки. Может быть, я бы стал разруливать типы через визитор, это бывает довольно удобно. Но даже события выглядят более красивым и стабильным решением, чем исключения в случаях, когда программных и аппаратных ошибок на самом деле не происходило.
Такие вещи ложатся достаточно высоко по стеку, так, чтобы перехватывать было некому.Что значит некому? Любой программист, который обычно использует исключения для индикации и обработки ошибок, может написать catch который будет ловить твой код возврата. Исключение - это ошибка, ну нельзя в него заворачивать код возврата. Я ещё более упрощу предлагаемую схему, просто как банальный пример использования перегруженного sqrt:
try { sqrt(x); } catch(DoubleException d) { } catch (IntegerException i) { } catch (Exception e) { }
У вас coupling между кодом license сервера и кодом приложения больше, чем в случае с ексепшенами.
Это не так, потому что ты предлагаешь аналогичные вещи: дерево классов extends BaseClass - дерево классов extends Exception - список событий. На мой взгляд последнее является самым нерасширяемым, но я могу быть неправ. Второе - просто неправильное применение исключений.
А кто сказал что со стороны сервера лицензий приходит ансвер? Сервер лицензий сериализует тот ексепшен, что был выкинут проксируемым методом и отдает его клиентской проксе. Никаких ансверов.
Я сказал, потому что в обычной практике в ответ на запрос к серверу приходит ответ. Или выкидывается исключение, если нету связи. Это две разные ситуации, которые по-разному обрабатываются.
Возможно. Мне вот кажется, что нормальная ситуация - это когда пользователя пускают внутрь. Все остальное - исключительная ситуация.в общем случае, смотря какая семантика у метода
если это именно чистый коннект, то да - исключения.
если же это - дай статус по лицензии, и по возможности законнектись - то нет, это уже не исключения.
на первое решение плохо кладутся предупреждения
т.е. надо идти именно от использования, если подразумевается, что лицензии даются разово, то лучше первое решение, если с лицензиями подразумевается постоянное истекание - то лучше второе
Но даже события выглядят более красивым и стабильным решением, чем исключения в случаях, когда программных и аппаратных ошибок на самом деле не происходило.но ведь БД кидают именно исключения, если не хватает лицензий.
или интерфейс к бд плохо спроектирован?
имхо, исключение - это событие о том, что что-то пошло не так, а уж почему оно не так (из-за ошибок, из-за пользователя, из-за окружения) - это не важно.
Но ты в своей архитектуре сразу закладываешься на невозможность выполнения этого действия. Практика показывает, что это заканчивается рефакторингом.Какая такая практика? Откуда статистика? Что за тестовый набор?
Давай возьмем популярные либы в которых есть метод наподобие login и посчитаем процент реализованных по вашему способу.
Так можно дойти и до того, что вызов любой боле менее серьезной функции будет проходить по вашей схеме.
Ну я предлагаю не совсем колбэки. Может быть, я бы стал разруливать типы через визитор, это бывает довольно удобно. Но даже события выглядят более красивым и стабильным решением, чем исключения в случаях, когда программных и аппаратных ошибок на самом деле не происходило.У тебя почему-то область применения исключений снижена. Почему - пока непонятно.
Вообще это конечно довольно холиварный вопрос. Многие люди просто не любят эксепшены, и их не применяют.
Вопрос красоты кода - настолько субъективен в мелочах, что я бы не стал серьезно об этом говорить. Из моего опыта - каждый пишет так, как привык. Соответсвенно, и нравится ему так, как он привык.
Что значит некому? Любой программист, который обычно использует исключения для индикации и обработки ошибок, может написать catch который будет ловить твой код возврата. Исключение - это ошибка, ну нельзя в него заворачивать код возврата. Я ещё более упрощу предлагаемую схему, просто как банальный пример использования перегруженного sqrt:Если программист сам написал вызов моего метода проверки лицензии, сам тут же написал неправильный кэтч, и думает почему все неработает, то ссзб.
try { sqrt(x); } catch(DoubleException d) { } catch (IntegerException i) { } catch (Exception e) { }
Ты видимо говоришь о проблеме, когда выброшеный эксепшен будет проглочен не предпологаемым кэтчем, выводящим пользователю большую ошибку на весь экран, а где-то посрединемежду вызовом и нужным обработчиком.
Посередине обычно находится какой-то контроллер, который пишется один раз, тестируется, и больше никогда не трогается. Этот контроллер вызывает функцию проверки лицензии. Если проверка успешная - то дальше вызывается код странички.
Код странички - это именно то место где пишет код мой "любой программист". Как бы он там ни располагал трай кэтчи, словить эксепшен от сервера лицензий ему не удастся.
По крайней мере в больших проектах проблема не в том, что код пишут дураки, которые вместо catch(ConcreteException) написали catch(Exception а потом схватились за голову.
Проблема в том, чтобы
а) изменения затрагивали как можно меньше кода, были максимально локальны
б) ошибки легко находились
В нащих вариантах со вторым пунктом все ок. А вот с первым пунктом у вас плохо. На простое количественное расширение - добавление нового кода возврата - надо прошерстить все места использования метода.
При большом проекте, когда есть куча модулей относящихся к другой команде, а у вас зачекаутена только малая часть кода, итд - вы либо сразу забьете, либо быстро заебетесь добавлять.
Это не так, потому что ты предлагаешь аналогичные вещи: дерево классов extends BaseClass - дерево классов extends Exception - список событий. На мой взгляд последнее является самым нерасширяемым, но я могу быть неправ. Второе - просто неправильное применение исключений.Да, у меня есть дерево ексепшенов, но у эксепшенов интерфейс стандартизован и не меняется при количественных изменениях. Если я задумаю кидать новый эксепшен в клиентском коде не обязательно что-то менять. В отличие от вашего БейзКласса.
Я сказал, потому что в обычной практике в ответ на запрос к серверу приходит ответ. Или выкидывается исключение, если нету связи. Это две разные ситуации, которые по-разному обрабатываются.Как вы напишите, так все и будет. Как можно обойтись без страшных свитчей я уже написал.
Если вы говорите о какой-то "обычной практике", то она мне пока не понятна. В моей обычной практике используется RMI, в котором таких проблем нет.
в общем случае, смотря какая семантика у методаАбсолютно согласен с вариантом только "дай статус по лицензии". Никаких эксепшенов в данном случае.
если это именно чистый коннект, то да - исключения.
если же это - дай статус по лицензии, и по возможности законнектись - то нет, это уже не исключения.
А вот "дай статус по лицензии, и по возможности законнектись" вообще комментировать не буду, ибо не знаю зачем такое нужно, и если где то такое есть, то это признак плохо продуманного интерфейса.
на первое решение плохо кладутся предупрежденияНу, удобоваримо. Или действительно отдельный метод - проверить статус, или сразу функция логина возвращает объект со всей необходимой инфой. Скажем, если у нас в коде есть ентити класс License, то будет вообще очень удобно.
В случае успеха ты получил ентити объект, сохранил куда то себе в контекст сессии, и имеешь всю инфу.
В случае неуспеха никакого лишнего траффика.
Количество проверок в коде минимально.
т.е. надо идти именно от использования, если подразумевается, что лицензии даются разово, то лучше первое решение, если с лицензиями подразумевается постоянное истекание - то лучше второеИдти действительно надо от использования, но про разовость и постоянное истекание мысль я не понял =)
но ведь БД кидают именно исключения, если не хватает лицензий.Я уже давно не говорю конкретно про этот случай. Здесь предлагается условно положительный код возврата запихать в исключение. Если нету лицензий, ремоутинг сможет сам выкинуть исключение и оно перевыкинется у клиента, я не вижу в этом проблем и могу с этим согласиться. Но положительные ответы от сервера разруливать через исключения нельзя - это приведёт к ошибкам. Ну и ещё см. мой пример по вычислению корня - к такой ерунде вполне можно придти, например, если запихать такую функцию в дженерик.
или интерфейс к бд плохо спроектирован?
Какая такая практика? Откуда статистика? Что за тестовый набор?Практика большая. Не путай низкоуровневую функцию с одним ответом и бизнес модель, которую, возможно, придётся расширять. Например, захотят две лицензии: evaluation и full. В твоём случае придётся писать два исключения FullLicense и EvaluationLicense, что вообще говоря странно.
Давай возьмем популярные либы в которых есть метод наподобие login и посчитаем процент реализованных по вашему способу.
Так можно дойти и до того, что вызов любой боле менее серьезной функции будет проходить по вашей схеме.
У тебя почему-то область применения исключений снижена. Почему - пока непонятно.
С каких это пор отказ от возвращения положительного результата через исключание является сниженной областью применения? Всему есть своё применение, и исключениями я пользуюсь во всех языках. Просто я против NotAnErrorException, и это вполне логично. Даже странно вести об этом спор или холи вар.
Посередине обычно находится какой-то контроллер, который пишется один раз, тестируется, и больше никогда не трогается. Этот контроллер вызывает функцию проверки лицензии. Если проверка успешная - то дальше вызывается код странички.... а дальше приходит заказчик и говорит, что лицензий будет шесть видов, причём расположенных древовидно. А дальше в каком-нибудь месте ловят базовое исключение. Да мало ли что, ну не решают исключения таких вот проблем.
В нащих вариантах со вторым пунктом все ок. А вот с первым пунктом у вас плохо. На простое количественное расширение - добавление нового кода возврата - надо прошерстить все места использования метода.
При большом проекте, когда есть куча модулей относящихся к другой команде, а у вас зачекаутена только малая часть кода, итд - вы либо сразу забьете, либо быстро заебетесь добавлять.
Нет, в нашем случае простое количественное расширение - это добавление одного метода обработки и одного класса. Ты всё равно из своих catch будешь вызывать какие-то методы, не будешь же ты писать весь код в одной функции. Я предлагаю привести пример кода, допустим, из дерева классов на 6 элементов - A, B : A, C : A, D : B, E : C, F : C и разрулить через исключения или вызовы вирт. методов. А дальше можно будет быстро показать, почему исключения не подходят и как они неудобны в этом случае. (Это если не принимать во внимание того, что они используются восвем не по назначению и потенциально ведут к проблемам.)
Практика большая. Не путай низкоуровневую функцию с одним ответом и бизнес модель, которую, возможно, придётся расширять. Например, захотят две лицензии: evaluation и full. В твоём случае придётся писать два исключения FullLicense и EvaluationLicense, что вообще говоря странно.Интересно, с чего придется писать два исключения? Нет, не придется. Я не собираюсь различать типы лицензий типом ексепшена. Это действительно нехилый мизюз.
Я оставлю количество исключений таким же, и добавлю еще один ентити класс.
Как я эти ентити классы буду различать на клинете - большой вопрос.
Может свитчем по типу/классу. А может если разных ентитей будет много, и мест кода где мне надо будет делать свитч по типу тоже будет много, тогда я допишу какую-то из разновидностей вашего метода, не удаляя свои два ексепшена.
Ты видимо просто меня не понимаешь.
Я не ставлю своей целью различать действительно положительные результаты с помощью ексепшенов. Я просто считаю непройденную авторизацию исключительной ситуацией. И считаю, что в данном конкретном случае модель описанная автором легко ложится на ексепшены.
Заранее закладываться на все причуды клиента, которые возможно появятся в будущем - достаточно дорого. И стоит ли делать это в данном случае, или провести потом при необходимости рефакторинг (это даже и не рефакторинг будет, просто дописывание кода) - вопрос, ответить на который может разве что автор.
Ну, удобоваримо. Или действительно отдельный метод - проверить статус, .транзакции не получается.
т.е. получили статус - было все ок.
начали коннектиться - все упало (т.к. лицензии успели истечь, их кто-то перехватил и т.д.).
или сразу функция логина возвращает объект со всей необходимой инфойкак ты предлагаешь эту функцию назвать?
Но положительные ответы от сервера разруливать через исключения нельзя - это приведёт к ошибкам.согласен
дти действительно надо от использования, но про разовость и постоянное истекание мысль я не понял =)если предполагается, что лицензии во время работы не меняются, то значит в программу вообще можно не добавлять обработку лицензий, а достаточно будет стандартного вывода о том, что вот такая-то функция не получилась, потому что было получено вот такое сообщение (вот такой exception)
т.к. ошибки связанные с лицензией получаются разовые, которые один раз исправляются и больше не возникают.
соответственно в этом случае достаточно обычного исключения.
если же лицензия может в любой момент кончиться, то получается, что необходимо делать красивую обработку этой ситуации, и здесь уже исключения будет недостаточно, т.к. будет хотеться показать/получить инфу без выполнения самого подключения, будет хотеться постоянно мониторить состояние и т.д.
если же лицензия может в любой момент кончиться, то получается, что необходимо делать красивую обработку этой ситуации, и здесь уже исключения будет недостаточно, т.к. будет хотеться показать/получить инфу без выполнения самого подключения, будет хотеться постоянно мониторить состояние и т.д.я не до конца тебя понял, но, конечно, лицензии могут кончится, если одновременно залогинится много пользователей. И естественно, на UI-е это должно корректно отображаться. Количество лицензий меняется со временем.
А ты подними throw'ы в те места кода, где переменной answer значение присваивается, а саму переменную выкинь.т.е. ты предлагаешь кидать исключения прям из середины метода(ов)? т.е. как только мы натолкнулись на ситуацию, когда надо кидать эксепшен, мы прям по месту кидаем его?
Если чуть больше рассказать о моей задаче, то увидим, что это не всегда работает, точнее появляется неприятный логический касяк.
Если нужна инфа о количестве лицензий для данной организации, то веб-сайт в первую очередь обращается к серверу лицензий, при этом результаты каждого успешного запроса сохраняются в базе данных сайта. Если сервер лицензий не ответил, то пытаемся найти инфу в базе. Сообщение "Сервис не доступен" выдаем только, если и в БД не оказалось инфы.
Подсчет количества одновременных пользователей тоже ведется через запись в БД (детали сейчас не важны).
Вся работа с БД объединена в одну транзакцию.
Если разделить на две транзакции:
1. Запись инфы от сервера лицензий
2. Регистрация пользователя, т.е. занимаем одну лицензию
Получаем неоднозначность, какую инфу использовать, ту которая с сервера или перечитывать из базы. Если перечитывать, то инфа может вообще исчезнуть — удалил какой-то проворный пользователь. Если использовать инфу с сервера, то надо рассматривать возможные проблемы, связанные с рассогласованность данных из пункта 1 и 2.
Короче, проще объединить в одну транзакцию. Транзакция короткая, поэтому все ок.
Вся работа с базой обернута в try\catch
try
{
...
}
catch(Exception)
{
transaction. Rollback
throw;
}
Так вот, если кидать эексепшен из середины кода, то транзакция откатиться. Ситуация — сервер лицензий ответил нормально, но на сайте уже много пользователей – будет обработана не верно, инфа с сервера лицензий не попадет в БД.
P.S. в случае колбеков тоже надо позабоиться о том, чтобы колбеки вызывались уже при закрытой транзакции, но это делается, подробнее напишу позже
P.S. в случае колбеков тоже надо позабоиться о том, чтобы колбеки вызывались уже при закрытой транзакции, но это делается, подробнее напишу позжеЧерез отложенное выполнение. Схематично это можно показать так
public void ConsumeLicense(string sessionId,
Action<int> successLicenseAction,
Action noFreeLicenseAction,
Action unAvailableLicensingServerAction)
{
Action result;
//открываем транзакцию
if (...)
{
if (...)
{
int daysBeforeExpired = ....;
result = delegate
{
successLicenseAction(daysBeforeExpired);
}
}
else
{
...
result = noFreeLicenseAction;
}
}
else
{
...
result = unAvailableLicensingServerAction;
}
//закрываем транзакцию
result;
}
Посередине обычно находится какой-то контроллер, который пишется один раз, тестируется, и больше никогда не трогается. Этот контроллер вызывает функцию проверки лицензии. Если проверка успешная - то дальше вызывается код странички.не, контроллер уже завязан на UШ-ай, он уже знает о страничках. И поэтому говрить о том, что контроллер редко меняется в отличии от страничек не правильно. Контроллер уже слишком близок к UI-ю, его правит "любой программист" . А вот логика работы с лицензией содержится в фасадных методах (или объектах на них можно наипсать нормальные юнит тесты.
не, контроллер уже завязан на UШ-ай, он уже знает о страничках.Я говорю не о контроллере, который в MVC применительно к вебу, и разруливает данные с формочки и передает их в модель.
Я говорю скажем о сервлет контейнере. Там, если ты сумеешь заюзать JAAS, тебе не придется на каждой страничке\контроллере каждый раз писать код вызывающий авторизацию.
т.е. ты предлагаешь кидать исключения прям из середины метода(ов)? т.е. как только мы натолкнулись на ситуацию, когда надо кидать эксепшен, мы прям по месту кидаем его?Вот теперь становится более менее понятно =)
Если чуть больше рассказать о моей задаче, то увидим, что это не всегда работает, точнее появляется неприятный логический касяк.
Если сюда добавить то, что вам наверняка хотелось как то выделить код удаленного обращения к ремоут серверу, который сейчас у вас наверняка живет в фасаде, то я даже не буду сильно плеваться =)
Вполне доброкачественный такой велосипед получился =)
Кстати, способ этот ваш активно используется например в SWING'е, который в этом топике уже упоминался.
транзакции не получается.Ну да, пожалуй поспешил я с заплевыванием "дай статус по лицензии, и по возможности законнектись".
т.е. получили статус - было все ок.
начали коннектиться - все упало (т.к. лицензии успели истечь, их кто-то перехватил и т.д.).
Но все равно и эти проблемы решаются. Например, модным в последнее время compareAndSet =)
public Action ConsumeLicense(string sessionId,
Action<int> successLicenseAction,
Action noFreeLicenseAction,
Action unAvailableLicensingServerAction)
{
Action result;
//открываем транзакцию
if (...)
{
if (...)
{
int daysBeforeExpired = ....;
result = delegate
{
successLicenseAction(daysBeforeExpired);
}
}
else
{
...
result = noFreeLicenseAction;
}
}
else
{
...
result = unAvailableLicensingServerAction;
}
//закрываем транзакцию
return result;
}
то это уже почти не колбек , т.е. два колбека , а фактически через колбеки только параметры функций проставляем
А в функциональном стиле че-то есть
Оставить комментарий
6yrop
Задача. Есть веб-сайт. Есть схема продажи прав доступа к этому сайту. Организация покупает определенной количество лицензий, число одновременных пользователей от этой организации не должно превышать количества купленных лицензий. Сайт делает запрос на другой сервер, который выдает количество купленных лицензий для заданной организации (общекорпоративный licensing server). Пользователей веб-сервер считает сам. Как это закодировать на C#?Хочется сделать некоторую API-шку, которая будет дергаться на aspx-страницах. API-ку можно будет покрыть unit-тестами, чтобы было все тип топ.
Требование такие:
1. Если есть свободная лицензия, выдать ее и разрешить показ сайта. Если срок лицензии истекает менее, чем через 30 дней, выдать предупреждение об этом.
2. Если нет свободной лицензии, выдать сообщение “Все лицензии заняты”
3. Если licensing server недоступен, написать что-то типа “Сервис недоступен”
C#
Java стиль
Java стиль лучше
1. Сигнатура метода ConsumeLicense более краткая. Если потребуется передать еще в какй-то метод, то передается только один объект.
2. Название методов лучше, чем название локальных параметром (легче рефакторятся и поддерживаются)
3. При добавлении еще одного метода сигнатура ConsumeLicense не распухает.