Хотелось-бы узнать, как кто решает архитектурную проблему работы с
сокетами.
В частности обработку приходящих событий, т.к. они не укладывается в
стандартную модель запрос / ответ.
Хочется раскидать логику обработки событий по классам и при этом не
писать гигантский switch на тысячу строк,
который будет разруливать все это дело, т.к. это становится лакомым
кусочком для вставки костылей.
Заранее благодарю.
Тут хорошо подходит паттерн Команда.
Денис Коляко
______________________________________________________________________
e...@timezero.ru | http://etcs.ru/ | http://timezero.com/
switch (event.code) {
case 1001:
break;
case 1002:
break;
case 1003
break;
...
case 1567:
break;
}
Кто будет заниматься этим безобразием и созданием комманд? На ум
приходит только фабрика с методом getCommand(eventCode:int):ICommand;
Возможо есть более элегантные решения.
В xml.
Использовать в протоколе имена (вместо id) команд и вызывать как методы.
> .as .txt .bin Не важно. Как уйти от свича на 1000 строк?
Я обычно пользую примерно следующую схему:
DataFormat.as
public static const ATTRIBUTE_COMMAND_ID:String = "id";
public static const START_GAME:String = "1001";
public static const END_GAME:String = "1002";
CommandsHandler.as
private static const handlers:Object = {};
public function registerHandler (commandId:String, handler:Function):Boolean {
if (handlers[commandId]) {
trace("Error: command registered "+commandId);
return false;
}
handlers[commandId] = handler;
return true;
}
public function handleCommand (command:XML):Boolean {
var commandID:String = command.attribute(ATTRIBUTE_COMMAND_ID);
var handler:Function = handlers[commandID] as Function;
if (handler) {
handler(command);
return true;
}
trace("incorrect command id");
return false;
}
Здесь схематично показано, но принцип понятен.
Константы выносятся в отдельный класс, от него наследуется этот класс.
Класс с константами называю обычно что-то вроде DataFormat и он
содержит все именования узлов XML, атрибутов и стандартных значений. И
от него наследуются и другие классы, активно использующие формат.
Этот класс обычно всё-таки портянка, но в нём ничего кроме констант нет.
В продвинутом случае можно сделать не константы (но оставить
именования капсом), а переменные и вначале сессии значения
синхронизировать с сервером.
Как итог, нигде в коде при разборе XML не используются строковые значения.
Все классы, имеющие обработчики команд, регистрируют их с помощью
registerHandler
Обработчик handleCommand может иметь другую логику, разумеется.
Это просто направление куда подумать, всё довольно индивидуально обычно.
>> Все классы, имеющие обработчики команд, регистрируют их с помощью
>> registerHandler
> И портянка switch..case трансформируется в портянку registerHandler. Те же
> яйца, только в профиль.
- боюсь, вы не поняли.
Если есть 300-500 команд, встает серьёзный вопрос. Их никуда не деть.
Как ни крути их останется столько же. И дело даже не в портянке. Если
бы портянка решала свои задачи, то ей были бы только рады.
Вопрос не в том, как сделать из 500 команд 5. Это невозможно и не нужно.
Вопрос в том, как организовать эти 500 команд так, чтобы минимально
заботиться об их обслуживании.
И мое предложение заключается в том, чтобы класс-обработчик независимо
от всего сам регистрировался бы и как-бы напрямую работал с серваком.
И тут помогает proxy.
С точки зрения разработчика:
например, появляется новая команда. Вместо того, чтобы лезть в
гигантский switch или еще чего, разработчик просто создает класс, или
в готовом классе метод, и регистрирует этот метод в CommandsHandler и
всё. Ну, то есть всё. Ничего больше.
Это много?
При этом CommandsHandler понятия не имеет о наличии обработчика. Если
его снести, то никаких ликов не будет. Связанность минимальная.
Получается некий proxy, который просто распределяет поступающую ему
инфу по заданным адресам, которые задекларированы потребателями. При
этом сам понятия не имея кто к нему обращается за услугами.
Не этого ли мы хотим добиться в результате?
я еще потеоретизирую.
любая команда, это как обычное письмо. Они имеют адрес назначения и
характерное содержимое, предназначенное адресату и никому иному. Если
письмо придёт по ошибке соседу, то он не поймёт какая нафиг баба Нюра
приболела и о какой свадьбе Светочки идет речь. Но правильный
получатель без труда поймёт о чем речь.
И вот у нас стоит задача каким именно образом будет работать почта.
Вариантов масса:
Можно вскрывать все письма, читать их, и принимать решение прямо на
почте должен ли получатель слать подарок на свадьбу Светочке или
попереживать за бабу Нюру.
- Но не замахается ли почта знать так много? Придётся нанять тысячи
сотрудников, чтобы они читали письма, изучали родственные связи
получателей и вместо них принимали решения. Абсурд.
Можно при постройке почты сделать именованые ящики для каждого
получателя. Тогда можно при получении письма быстро его сбрасывать в
соответствующий ящик и дальше пусть сам получатель время от времени
заходит на почту и смотрит нет ли ему письма.
- Но это тоже бред. Если будет построен новый дом, то нужно идти на
почту и устанавливать там новый ящик. Плюс к этому, всем жителям
района придётся постоянно ходить на почту проверять ящик. В итоге,
холостых ходок будет очень много.
Я предлагаю по сути очень простую вещь: почта не имеет никаких ящиков
и понятия не имеет о том, куда доставлять письма, а уж тем более как
их прочесть и отреагировать на них.
Но как только появляется новый дом на районе, его хозяин один раз идёт
на почту и говорит, что если придет письмо на имя Александра Немцова,
то будьте добры его доставить в дом 3 по улице Советских Флэшеров.
При получении он сам его вскроет, прочтет и примет решение как
отреагировать на болезнь бабы Нюры и на свадьбу Светочки.
Каждый занимается своим делом. Почта лишь читает адрес и доставлет
письмо. Получатель решает как реагировать. Если получатель переехал,
ему достаточно уведомить почту. И так далее.
Логично, просто, гибко.
Почта не должна следить за тем, где живёт Александр Немцов - это его
задача сообщить почте свой адрес, если он хочет получать письма.
Почта не должна лезть и читать содержимое письма - не ей оно
предназначено и не ей решать как реагировать на него и что написать в
ответ.
Александр Немцов не должен бегать каждый час на почту проверять свой
ящик - почта должна доставить письмо ему в руки.
Всё просто.
> Использовать в протоколе имена (вместо id) команд и вызывать как методы.
- честно говоря, я бы так не делал.
Любое переименование метода влечет за собой изменение формата данных и
наоборот. Ставить формат данных в зависимость от клиента или от
сервера неверно и усложняет обслуживание кода.
Во вторых, насколько я понимаю, все методы обработчики либо должны
жить в одном классе, либо требуется использование полного пути к
обработчику вида com.domain.game.view.parseCommand. Оба решения
некрасивы.
> Паттерну Коммандный Процессор лет эдак вдвое больше чем флешу, он безусловно
> полезен и практичен.
- я даже не знал, что такой паттерн есть :)
> Однако вы утверждаете что от портянки никуда не деться, предлагая ее
> "прятать" за динамическое наполнение.
- по-сути да. Портянка образуется на лету в рантайме. Но разве это
плохо? Делается она один раз, много не ест, работает быстро,
обслуживается программистом легко, формат данных можно менять хоть на
лету.
Что еще надо? С чем бороться?
- честно говоря, я бы так не делал.
Любое переименование метода влечет за собой изменение формата данных и
наоборот.
Ставить формат данных в зависимость от клиента или от
сервера неверно и усложняет обслуживание кода.
Во вторых, насколько я понимаю, все методы обработчики либо должны
жить в одном классе, либо требуется использование полного пути к
обработчику вида com.domain.game.view.parseCommand. Оба решения
некрасивы.
> Бороться надо с bad code smells, коими являются любые длинные портянки -
> явные или неявные.
- с каких это пор динамические коллекции стали пахнуть?
В чём именно заключается дурной запах?
> На двести инструкций надо написать двести регистраций -
> вот именно этот момент и пахнет.
- я бы добавил, что на двести инструкций нужно написать двести обработчиков :)
Нет, ну следуя логике дзен-дизайна, идеальный код - отсутствие кода.
Имеет массу преимуществ: гарантированно нет багов, прост в
производстве и поддержке, понятен при изучении.
Но всё-таки.
> А быть независимым от формата данных так вообще невозможно.
> id или имя — это по барабану, изменение того или другого требует
> соответствующих действий и на сервере и на клиенте.
- в моем варианте хоть на лету можно менять формат. Не структуру
данных конечно, а именования узлов, атрибутов, стандартные значения.
Это и есть достаточная независимость от формата. Максимально возможная
в случае применения XML как транспорта.
Можно выложить файлик с описанием формата и использовать его и
серверному и клиентскому программеру - любой может менять значения
констант без последствий. Его можно вкомпиливать или юзать на лету,
тоже не важно.
> Вложенные команды могут решить проблему.
- есть всего две альтернативы: либо все обработчики держать в одном
классе, либо использовать полный путь.
Первый вариант
- портянка, от которой справедливо мечтает избавиться автор. И похуже свича.
Второй вариант
- засовывание в формат совершенно ненужных данных о путях к классам;
- зависимость кода от формата и наоборот - самый обычный рефакторинг
на клиенте превращается в довольно забавную процедуру с участием
серверных программистов - они будут рады;
- а если и серверные программисты также поступят, то их рефакторинг
станет и твоим;
- лишняя нагрузка на проц за счет необходимости поиска метода по его пути.
- да и вообще не нравится он мне :)
> Оппа! Магия! Карта есть, а регистрации нет. Никаких тебе полных путей,
> никаких God Class со всезнанием о всех командах etc
- а подписываться на событие не надо?
>> - а подписываться на событие не надо?
> Судя по документации, нет.
- как мило. Он всех вещателей в проекте слушать будет?
Последние архитектурные фреймворки (Spring AS, Parsley, Swiz, Mate(?))
активно используют метаданные для самостоятельного разруливания ситуации.
Например, в классе можно объявить такую конструкцию:
[Command("someCommand")]
public function command(id:uint, data:String):void {}
И некоторый сборщик, который "над" всем, подпишет оповещать о пуступающих
командах с именем someCommand эту функцию, при этом будет основываясь на
типах параметров парсить входящие данные и громко ругаться, если что пошло
не так.
По идее вот оно описание: someCommand (id:uint, data:String).
Куда-то прячем еще соответствие id команды и имя команды. Хотябы в тот же
тэг.
О чем говорит Денис, и что реализовано у нас — это по сути то же самое,
только метатэг переносится в XML и типы данных описываются там же.
Получается что-то типа:
<command name="someCommand" id="..">
<param name="id" type="uint"/>
<param name="data" type="String"/>
</command>
А некоторый сборщик, который "над" всем, пытается вызвать публичный метод с
именем someCommand / подписанные на эту команду методы, и передать им
распарсенные данные.
XML хорошо тем, что оно все в одном месте. Еще, можно выдать серверникам и
они на его основе скриптом сгенерят себе код, который посылает/разгребает
все те же команды. Или наоборот. В зависимости кто у вас круче флэшеры или
серверники.
от switch case на обработку сокета уходить не нужно, бо невозможно с
точки зрения логики. Т.к. нельзя подписываться всем контроллерам на
все события.
Каждой комманде с сервера ставится в соответствие Event. Каждый
контроллер подписан только на необходимые ему события. Если необходимо
одно событие обработать двумя контроллерами, причем в определенной
последовательности, то вешается промежуточный слушатель.
В моем случае switch-case можно написать один раз по спецификации с
сервера и благополучно забыть о нем. Даже если вид ответа изменится
потом, то это затронет только контроллер. Events делают свое дело.
Да, и считаю что switch-case существует именно для таких случаев вроде
обработки сокета. А если привязать типизацию сервера к типизации
клиента, как было описано выше, то получится зоопарк и никак иначе,
тут поможет только общий workflow разработки, который затрагивает и
клиент и сервер, но это в разы усложняет систему, что, конечно,
красиво, но эффективно ли?
Вот мне, например, не нравится, что он "пытается" вызвать. Тут должна
быть определенность, вызывает или не вызывает.
Ну и еще связь на мой взгляд слишком жесткой получается.
an> О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫ О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫ О©╫О©╫О©╫О©╫.
an> О©╫ О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫ О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫
an> О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫ О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫. О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫
an> О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ - О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫ О©╫О©╫О©╫О©╫О©╫О©╫.
О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫
О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫.
О©╫ О©╫О©╫О©╫О©╫О©╫О©╫, О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫: О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫
О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫.
--
Best regards,
Maxim mailto:md...@mail.ru
> Если его снести, то никаких ликов не будет. Связанность минимальная.
Чтобы этот класс компилировался, его всё-таки придётся упомянуть где-то ещё.
А если его снести, то придётся удалить и в том месте, где упомянули.
Связанность, конечно, всё равно не большая, но она есть.
> Чтобы этот класс компилировался, его всё-таки придётся упомянуть где-то ещё.
> А если его снести, то придётся удалить и в том месте, где упомянули.
>
> Связанность, конечно, всё равно не большая, но она есть.
- отсюда вывод, что всем классам проекта присуща связанность :)
Процесс регистрации кодируется один раз.
Сущности просто вызывают метод: зарегистрируйте меня. Всего одна строчка.
Да, если 200 сущностей, то в сумме будет 200 строчек - но не всей
кучей, а по одной в каждом классе.
И никуда от этого не деться: как-то же мы должны сообщить, что вот
именно этот класс отвечает вот за эту команду.
По поводу того, кто должен отвечать за регистрацию: тут вопрос
спорный. И в том и в другом случае есть свои плюсы и минусы.
Но централизованное хранилище будет в любом случае, ведь, как я уже
говорил, если класс нигде не упомянут, то компилятор его и не
учитывает.
А значит таки где-то придётся упомянуть все классы, ответственные за
обработку команд.
> Дело не в кол-ве строчек, а в ответственности. Кто-то должен быть
> ответственным за регистрацию - кто?
- я выше раписывал пример про почту.
Сообщить почте где ты живешь - твоя обязанность.
> А нужен ли такая бизнес-единица, назначение которой "бумажки с места на место перекладывать"?
- нужна. Альтернатива - только создание индивидуального сокет
соединения каждым обработчиком.
Но это и накладно и невозможно и, даже если бы было возможно, то
чревато ошибками - в таком раскладе возможно изменение
последовательности прихода команд.
On Mar 14, 9:56 am, Ivan Dembicki <ivan.dembi...@gmail.com> wrote:
> следуя логике дзен-дизайна, идеальный код - отсутствие кода.
> Имеет массу преимуществ: гарантированно нет багов, прост в
> производстве и поддержке, понятен при изучении.
в цитатник.
Из практики у меня сложилась примерно такая схема:
глобальная карта выполняет сл. функции:
1) инстанцирует мегаменеджера и рутовую модель :) - но "мега" в
хорошем смысле, он рулит только ситуации касающиеся всего приложения в
целом и пишет результаты своих действий в рутовую модель
2) весь обмен с сервером лежит в ней (ибо удобно)
3) получает события уровня приложения, вызывает методы мегаменеджера
для их обработки
инъекторы зависимостей обычно выношу в отдельную карту - так их проще
обслуживать
каждый вид (достаточно обособленная визуальная часть приложения)
инъектируется собственным менеджером и моделью (которая связана с
рутовой моделью через инжекторы) - чтобы в самом визуальном компоненте
ничего кроме собственно визуальной части и интерактива не было (так
проще модифицировать приложение).. т.е. здесь что-то вроде
Presentation Model
вид знает о менеджере и вызывает его публичные методы, менеджер не
знает о виде ничего.
В виду темы обсуждения - скорее всего был бы сделан один обработчик
сокетного события типа ServerRequestEvent.IncomingData и второй для
ServerRequestEvent.OutgoingData
по ним бы дергались соответствующие методы менеджера приложения -
который бы внутри имел инстанс менеджера соединения и :)) таблица
соответствий типов сообщений (портянка) размещалась бы в нем или во
внешнем файле, который бы грузился или компилился не принципиально..
всем остальным как бы до этого дела вообще нет.. пришли данные,
обработались соотв. манагером и сложились в модель - из модели кому
интересно, те их и растащили..
получили пользовательский ввод - обработали на уровне вида и его
адаптера - записали в собственную модель, приняли решение о
необходимости оповестить остальное приложение - отдиспатчили соотв.
событие. карта поймала - дернула менеджера приложения - тот принял
решение по ситуации, дернул RPC и/или сложил данные в модель.
Круг замкнулся.
--
С уважением, Скорик Андрей. andrew...@gmail.com
> [оффтопик]
> Сообщать почте я ничего не должен - почта доставляет посылку по адресу.
- это совковая система. В нормальной системе достаточно прийти на
почту и попросить всю корреспонденцию на мое имя пересылать по новому
адресу.
Если такой системы нет, то после переезда письма будет получать не тот
адресат или они забьют прочтовый ящик под завязку.
> Выдачей адресов занимается БТИ :) Собственно, примерно так оно и обстоит с
> метатэгами.
- ну давай так: в итоге, мы ведь всё равно получаем swf и там всё это
проходим, причем не всегда понятно и управляемо.
> почта, которая посылки из Китая в Хабаровск [...] возит через Москву (то есть через
> гигантский мегаменеджер).
- не совсем так. В моем предложении, опять же по аналогии, есть один
таможенный пункт с Китаем, и тут же сортировочная почты. Каждый
получатель сообщает свой адрес и напрямую оттуда получает
корреспонденцию из китая.
> Плюсы - централизация и... эээ... все, плюсы кончились.
- о какой централизации идёт речь?
давай так:
Вариант 1.
каждому классу создается отдельное сокетное соединение. Децентрализация полная.
Итог: 400-500 сокет-соединений (допустим, что это возможно). Каждое
соединение нужно создать, обслуживать, обрабатывать ошибки, закрывать,
и т.п.
В аналоги с почтой - каждому получателю вменяется в обязанность
таскать с собой почтовое отделение. Нужно ему это? Нму почта нужна, а
не почтовое отделение.
Вариант 2.
создается одно сокетное соединение. Дальше как ни крути, можно
сказать, что почта приходит в страну централизованно. Вопрос лишь в
том, сколько этапов потребуется для того, чтобы доставить почту
получателю.
а) в моем варианте каждый получатель сообщает этому центру где он
живет и всё. Если адрес сменился, то получатель сообщает это на почту.
В итоге, отправителю достаточно указать имя получателя. Дальше, как
только почта пришла, получатель немедленно и без дополнительных
посредников ее получает. Метод: либо через подписку на событие, либо
через регистрацию обработчика.
Итог:
при создании получателя требуется уведомить почту о себе. При смене
адреса не требуется.
б) можно раздать всем адреса. Отправитель, помимо имени получателя
должен знать где живёт получатель. Если вдруг изменится адрес, то пока
отправитель не узнает новый адрес, почта будет ошибочно доставлять
корреспонденцию. Также несколько увеличивается нагрузка на почту,
поскольку она должна вычислить адрес.
Итог:
при создании или изменении адреса получателя требуется уведомить
отправителя в Китае.
в) можно собрать представителей получателя на почте, раздавать им
почту и пусть они сами заботятся как ее доставить получателю. Но будут
ли это получатели? Нет. Это будут посредники. Их будет много и они все
будут толкаться на почте.
Реализация: switch или множество обработчиков, одноименных с командой.
Итог:
при создании получателя требуется создание посредника. Почта будет
приходить через посредника.
> Минусы - чумовое время доставки и нереально завышеная стоимость
- давай пройдём по цепочке любого варианта и ты увидишь, что
предложенный мною вариант быстрее всех.
На мой взгляд не стоит прятать логику приложения ни за метадатой, ни
выносить ее во внешние файлы.
Этим мы лишаемся родной проверки компилятора. Даже если представить, что
мы пишет плагины к IDEA / Eclipse, которые
будут в курсе предназначения наших xml или java тулзы вместе с build
скриптами для проверки целосности метадаты,
мы получаем кучу геморроя с разработкой и поддержкой этих решений в будущем.
Собственно у меня вопросов больше нет. Всем спасибо.
> Плюсы - централизация и... эээ... все, плюсы кончились.
- низкая стоимость разработки:
требуется только один центр приема и обработки данных, ошибок,
подключений и т.п.
- низкая стоимость смены транспорта:
при переходе от XML к другому формату или при изменении формата меняем
код только в одном месте.
- высокая скорость доставки:
после попадания данных в ролик только один посредник. Меньше
невозможно технически - количество сокет соединений ограничено.
И еще раз:
на выхлопе мы в любом случае имеем swf. Так или иначе, метатеги там
или подписка, всё равно в итоге будет хоть один посредник - тот, кто
сидит на сокете и раздает дальше.
В моем варианте он отдает напрямую, без создания новых сущностей.
В варианте с метатегами я не уверен, скорее всего будет еще один
посредник как минимум.
Регистрация в моем варианте - стандартный код, хорошо поддерживаемый
редакторами - одна строчка. Есть возможность отписки на лету.
Метатеги - нестандартная вешь, плохо поддерживаемая редакторами. И
кстати, тоже одна строчка, как ни крути. На лету не отпишешься. В
итоге просто изврат ради изврата. Чтобы все кругом знали, что мсье
знает толк в извращениях.
> Реализация IoC через метатэги очень вкусная.
> Позволяет избежать толпы ненужного кода и кучи тупых проблем.
> Нужно всего лишь один раз написать/взять готовый большой класс для работы с
> ними.
Вот смотри:
[EventHandler(name="saveUser")]
Скажзи плз, какой редактор даст автокомплит хоть на одном из слов?
Какой редактор проверит правильность написания этих слов?
Честно говоря, я не очень понимаю о чем речь (а это тоже минус
технологии - усложнение, удорожание), не знаю кто ее поддерживает и
какие подводные грабли меня там ждут.
Возможно где-то их применение оправдано. Но не в этой теме точно.
On Mar 15, 5:50 pm, Ivan Dembicki <ivan.dembi...@gmail.com> wrote:
> Честно говоря, я не очень понимаю о чем речь (а это тоже минус
> технологии - усложнение, удорожание), не знаю кто ее поддерживает и
> какие подводные грабли меня там ждут.
можно ж и погуглить, например http://blog.gtuhl.com/2007/03/05/flex2-custom-metadata/
Если адрес меняется получатель обычно сообщает отправителям, а на
почту только в том случае, когда проблематично уведомить всех
отправителей. Почта не работает с именами, потому что адрес как путь к
файлу, позволяет письму сначала отправиться в город, потом в
конкретное отделение по индексу а потом уже ищется конкретный адресат.
> б) можно раздать всем адреса. Отправитель, помимо имени получателя
> должен знать где живёт получатель. Если вдруг изменится адрес, то пока
> отправитель не узнает новый адрес, почта будет ошибочно доставлять
> корреспонденцию.
Отправитель всегда должен знать адрес получателя! В обычной, улиточной
почте имя получателя рассматриватся как часть адреса, и когда вы
вынимаете письмо из ящика, вы свичом перебираете, кто тут из нас Иван
Иваныч, или, если письмо требует личного вручения адресату, это делает
почтальон, а при смене адреса вы само собой сообщаете об этом, но я не
могу представить себе необходимость смены адреса в рантайме, куда
обработчикам нужно переезжать за время работы приложения?
> в) можно собрать представителей получателя на почте, раздавать им
> почту и пусть они сами заботятся как ее доставить получателю. Но будут
> ли это получатели? Нет. Это будут посредники. Их будет много и они все
> будут толкаться на почте.
Это опять совковый подход, посредник это не тот который только
мешается, а которому делегируются некие функции дабы я не
заморачивался с почтовыми конвертами, мне интересно только содержимое
письма, и я не хочу знать как надо распаковывать/запаковывать конверты
и вообще как работать с почтой, я просто прошу посредника прочитать
мне письмо и диктую ответ. А если посредник может работать с
несколькими клиентами, то тогда их на почте будет толкаться всяк
меньше, чем реальных получателей.
> - давай пройдём по цепочке любого варианта и ты увидишь, что
> предложенный мною вариант быстрее всех.
Быстрее что? Обработка пакета, регистрация адресов, или разработка?
Для более менее сложной системы обменов данными небходим протокол
обмена. Еще где-то выше было сказано, удобное решение это
синхронизация модели данных сервера и клиента, и серилизация этих
данных, чтобы не гонять по сети длинные строки с именами комманд.
Портянки с адресами сматываются в айдишники которые разбиваются по
маске [сервис][служба][комманда] Пакет состоит из объекта данных и
заголовка, в заголовке по мимо прочего пишется адрес и пока объект не
дойдет до комманды обработчика, он никак не обрабатывается читается
только заголовок, конверт с адресом, и по нему письмо сначала попадает
в сервис оттуда в службу и до конкретной комманды доходит уже
распечатаный объект. С первого взгляда может показаться слишком сложно
и хочется побыстрее напрямую доставить, ну так ничто не мешает
разместить все в одном, просто когда портянка вырастает мы ее легко
сможем разделить на отдельные сервисы, которые уже можно
регистрировать динамически.
IDEA даст сразу на двух)
> можно ж и погуглить, например http://blog.gtuhl.com/2007/03/05/flex2-custom-metadata/
- поверь, я при необходимости, могу написать такую же статью про метедату.
Дело то не в том, что я должен знать как работать с метаданными.
Дело в том, что я должен изучить чьё-то решение, основанное на метаданных.
Плюс заморочиться с тем, чтобы эти метаданные не потерялись при компиляции.
А погуглить можно и на тему Большого Взрыва. Но не факт, что после
этого ты сможешь назвать себя физиком.
> IDEA даст сразу на двух)
- на двух стандартных.
На пользовательских не даст.
> Если адрес меняется получатель обычно сообщает отправителям, а на
> почту только в том случае, когда проблематично уведомить всех
> отправителей.
- а представь, что ты вообще не знаешь, кто отправитель.
Плохая почта письмо потеряет. Хорошая доставит.
Мы ведь хорошую почту хотим, правда?
> Почта не работает с именами [...]
- Плохая почта не работает с именами. У хорошей нет проблем.
А мы можем сделать хорошую. Зачем копировать поведение плохой?
Мы ведь хорошую почту хотим, правда?
> Отправитель всегда должен знать адрес получателя!
- весьма спорное утверждение. Даже на советской почте можно сделать
абонентский ящик и получать письма на него. И там же дать распоряжение
о том куда им сообщать, если что-то пришло. Если это реально сделать у
нас, то почему бы не сделать?
Мы ведь хорошую почту хотим, правда?
> я не могу представить себе необходимость смены адреса в рантайме, куда
> обработчикам нужно переезжать за время работы приложения?
- вышел игрок из мультипользовательской игры - убили экземпляр класса.
Зашел - создали. И фантазию даже не особо пришлось напрягать.
> я не хочу знать как надо распаковывать/запаковывать конверты
> и вообще как работать с почтой, я просто прошу посредника прочитать
> мне письмо и диктую ответ.
- так и я о чем. Мы делаем систему. Так или иначе в этой системе
должны быть расписаны все обязанности. Вопрос лишь в том, чтобы не
насоздавать лишних посредников и где правильно расположить тот или
иной функционал.
Нефига тащить почту каждому в дом. Но и почта не вправе читать мои письма.
> А если посредник может работать с
> несколькими клиентами, то тогда их на почте будет толкаться всяк
> меньше, чем реальных получателей.
- да лишние они и всё тут. Даже один - уже много.
> Быстрее что? Обработка пакета, регистрация адресов, или разработка?
- всё.
> Для более менее сложной системы обменов данными небходим протокол
> обмена. Еще где-то выше было сказано, удобное решение это
> синхронизация модели данных сервера и клиента [...]
- кто бы был против.
Но, во первых мы обсуждаем не протоколы данных, а систему приема
данных при готовом протоколе. К тому же, не факт, что:
а) протокол вообще можно поменять
б) другой протокол будет лучше отвечать требованиям проекта.
> Портянки с адресами сматываются [...]
- да, красиво. Но не всем походит.
Выбор протокола - разговор отдельный и там свои требования.
On Mar 15, 8:05 pm, Ivan Dembicki <ivan.dembi...@gmail.com> wrote:
> Hello Kuril,
>
> > IDEA даст сразу на двух)
>
> - на двух стандартных.
> На пользовательских не даст.
и что, такая великая проблема сделать пользовательский? Просто не
занимался таким вопросом, но уверен, что если есть вообще такая
поддержка, то расширить ее можно!
Пример хорошей почты, которая работает с большим количеством имен
есть? На ум приходит только DNS, но это дополнительная сущность, но мы
ведь не хотим плодить сущности правда? Тем более там имя тоже нельзя
создать так просто, само имя должно разбиваться на части.
> > Отправитель всегда должен знать адрес получателя!
>
> - весьма спорное утверждение. Даже на советской почте можно сделать
> абонентский ящик и получать письма на него. И там же дать распоряжение
> о том куда им сообщать, если что-то пришло. Если это реально сделать у
> нас, то почему бы не сделать?
> Мы ведь хорошую почту хотим, правда?
Извините, абонентский ящик это и есть адрес, только конечный адресат
обозначен как номер а не имя фамилия, в чем спорность утверждения?
> > я не могу представить себе необходимость смены адреса в рантайме, куда
> > обработчикам нужно переезжать за время работы приложения?
>
> - вышел игрок из мультипользовательской игры - убили экземпляр класса.
> Зашел - создали. И фантазию даже не особо пришлось напрягать.
Если на каждый вход/выход игрока регистрируется/удаляется что-то типа
комманды, то это плохо спроектированная мультипользовательская игра!
> > я не хочу знать как надо распаковывать/запаковывать конверты
> > и вообще как работать с почтой, я просто прошу посредника прочитать
> > мне письмо и диктую ответ.
>
> - так и я о чем. Мы делаем систему. Так или иначе в этой системе
> должны быть расписаны все обязанности. Вопрос лишь в том, чтобы не
> насоздавать лишних посредников и где правильно расположить тот или
> иной функционал.
> Нефига тащить почту каждому в дом. Но и почта не вправе читать мои письма.
Так и я о чем, посредник просто не в состоянии прочитать письмо,
потому что он умеет читать только адреса, а вот я не хочу учиться
читать адреса, потому что моя задача сосредоточиться на содержимом
письма. Если в вашей системе логически возникает новая сущность, то
глупо игнорировать ее и прятать в другой сущности, с которой она
только связана, но сама ей не является.
> > Быстрее что? Обработка пакета, регистрация адресов, или разработка?
>
> - всё.
Чтобы было всего много вкусно и бесплатно так не бывает, по закону
сохранения энергии, если где-то прибудет обязательно где-то убудет,
надо это иметь ввиду и расставлять приоритеты!
> > Для более менее сложной системы обменов данными небходим протокол
> > обмена. Еще где-то выше было сказано, удобное решение это
> > синхронизация модели данных сервера и клиента [...]
>
> - кто бы был против.
> Но, во первых мы обсуждаем не протоколы данных, а систему приема
> данных при готовом протоколе. К тому же, не факт, что:
> а) протокол вообще можно поменять
> б) другой протокол будет лучше отвечать требованиям проекта.
>
> > Портянки с адресами сматываются [...]
>
> - да, красиво. Но не всем походит.
> Выбор протокола - разговор отдельный и там свои требования.
Где там у сокета готовый протокол? TCP обеспечивает только доставку
байтов и все, тут нужен новый прикладной уровень, и разбор байт
массива будет в любом случае протокол, просто когда надо отправить
пару xml об этом не задумываешься и твой протокол примитивен, а когда
разнообразие этих xml увеличивается, возникают такие вопросы. Если
сделать сделать синхронизацию данных, когда сервер посылает объект и
клиент всегда знает как этот объект читать, то есть получает объект
as, то написание протокола сильно упрощается!
> Пример хорошей почты, которая работает с большим количеством имен есть?
- выше я предложил вариант, который прекрасно работает на заданных 400
командах.
Единственный вопрос - уникализация имен команд. Здесь он не стоит.
Когда нас попросят запрограммировать Интернет2, тогда и будем думать о
том, как разрулить.
> Извините, абонентский ящик это и есть адрес, только конечный адресат
> обозначен как номер а не имя фамилия, в чем спорность утверждения?
- в том, что я говорю, что достаточно иметь имя команды вида "foo",
чтобы вызвать метод fooHandler в классе
com.domain.project.folder.class, а не знать полный путь к нему вида
"com.domain.project.folder.class.fooHandler", как предлагалось Денисом
Коляко выше.
> Если на каждый вход/выход игрока регистрируется/удаляется что-то типа
> комманды, то это плохо спроектированная мультипользовательская игра!
- не нам решать. Это зависит исключительно требований проекта, его
особенностей. В целом ряде случаев это может быть оправдано и
эффективно.
И опять-же это лишь возможность, а не требование. Возможность всегда
лучше иметь, чем не иметь.
> Если в вашей системе логически возникает новая сущность, то
> глупо игнорировать ее и прятать в другой сущности, с которой она
> только связана, но сама ей не является.
- да слава богу. На самом деле это лишь вопрос кого ты считаешь
получателем - какую-нибудь вьюху или модель данных. Твое право
выделить хоть специального читателя - мое предложение никак не
регламентирует это и оставляет право архитектору приложения самому это
решить.
> Чтобы было всего много вкусно и бесплатно так не бывает
- бывает. Если тупо, то медленно и дорого. Если по уму, то быстро и дешево.
> Где там у сокета готовый протокол? TCP обеспечивает только доставку [...]
- вопрос в первом письме прочти плз. Мы вроде как его обсуждаем.
Если интересно пообщаться на тему форматов, давай создадим новый топик.
эта зависимость тоже должна быть минимизирована. что достигается
написанием адаптера для вида. т.е. его собственной модели, которая
преобразует данные модели приложения в тот формат который понятен и
удобен для конкретного вида/компонента.
тогда один и тот же один раз сделанный визаульный компонент может быть
использован в разных версиях приложения/приложениях с разными
моделями. задача переноса сводится к модификации/написанию адаптера
On 16 мар, 12:43, k0t0vich <b_konstan...@list.ru> wrote:
> т.е. по сути - сервер является контроллером - который изменяет данные
> модели
Я предлагаю рассмотреть вариант, в котором сервер служит частным
случаем источника данных. Подмените/дополните питание приложения еще
каким-либо источником данных - файл, LocalConnection,
ExternalInterface, flashvars, пользовательский ввод - суть от этого не
изменится. А контроллер, который в MVC, непосредственно воздействует
на модель, анализируя входные поток(и) данных. В конце концов никто не
запрещает контроллеру вообще игнорировать какой-либо источник данных в
своей работе.
Т. о. я бы уточнил, что сервер является контроллером лишь
опосредованно.
> У варианта Ивана есть серьезный минус -- зная сигнатуру команды очень
> сложно найти место в коде, которое ее обрабатывает.
- этот недостаток есть только при условии, если используются строковые
данные при регистрации.
В моем предложении есть четкое указание на необходимость использования
класса с константами.
В этом случае достаточно открыть этот класс, найти в нем нужную
команду и посмотреть где была использована константа (Ctrl+R)
> Также непонятно
> что делать, когда нет обработчиков у команды или их несколько.
- ну, всё зависит от стратегии.
Я бы не разрешал наличие двух обработчиков, а при отсутствии
обработчика кидал бы дебаг сообщение.
> Не будет работать. Потому что написание кода оно сейчас, а константы
> могут понадобиться в некотором будущем, на их написание будут
> забивать.
- ну, если на такие вещи забивать, то нет смысла предлагать что-то,
потому, что на что угодно можно забить.
> Но чтобы приложение не стало слишком громоздким нужно группировать обработчики
- да, вполне реально и разнести на группы. В определенных ситуациях
это будет полезно.
можно вообще пойти по бинарному дереву и для каждого бита свой иф )
а вообще если много-много чего нужно обрабатывать то тут нужно не
архитектуру придумывать.
все архитектурные решения уже придумали до нас.
тут важное автоматизировать процесс:
например:
вам нужна новая комманда от сервера к клиенту или от клиента к серверу
- вы ее вписываете в ваш документ это может быть просто xls
- она парсится какми-то образом, пусть даже скриптом на перле
- этим парсером генерятся серверные и клиентские классы наследники
вашей системмы
- так-же перегенеривается портянка соответствий (в хмл, динамичная или
свиче статичная - неважно)
-- по вкусу можно еще клиентский и серверный код задокументировать и сбилдить.
по итогу вы пишите в доке:
myMegaCommand(param1:int,param2:int,param3:String):int | это сервер
просит клиенета сложить два числа param1 и param2, param3 просто
строка
и у вас сразу две новые либы на клиенте swc и на сервере jar
а программисты видят эти изменения, апдейтятся и могут сразу
на сервере:
IServerCommand command = new myMegaCommand(5,10,"asdsad");
command.assignResponceHandler(myMegaCommandHandler);
command.execute();
на клиенте:
SocketClient.instance.addEventListener(SocetClientCommands.MY_MEGA_COMMAND,
onMyMegaCommand); // MY_MEGA_COMMAND - константа сгенерена скриптом
private function onMyMegaCommand(e:onMyMegaCommandEvent):void { //
onMyMegaCommandEvent - класс сгенереный скриптом
trace(e.id, e.param3); // e.id - нужно продумать уникальность, чтобы
можно было отличить две одновременные одинаковые комманды
var responce:IClientResponce = new MyMegaCommandResponse(e.id,
e.param1 + e.param2) // MyMegaCommandResponse - сгенеренный класс
SocketClient.instance.processPesponce(responce)
}
А еще передавать в запросах клиент-сервер нужно ведь и сложные типы -
их тоже нужно автоматом генерить.. и все это дело автоматизировать
я бы пошел таким путем. лучше месяц потерять потом за пять минут долететь.
Вот честно, не понимаю, нафига гененировать тучу монструозных и бесполезных ивентов, когда можно обойтись строчкой:
(this._client[command.name] as Function).apply(this._client, command);
Денис Коляко
______________________________________________________________________
e...@timezero.ru | http://etcs.ru/ | http://timezero.com/
тут сложность в разрастании класса this._client для которого нужно
создать, например 200 методов. в другом проекте будет невозможно
повторное использование кода - например там нужны только 2 из 200
команд..
я использую c protoBuf
message:Message = Message.getMessage(byteArray); // сериализуем в
нужный класс сообщения
message.execute(this.model,this.controller);
в клиенте имеется статичная ф-ция регистрации алиасов: - для каждого
проекта она может быть своя. в итоге мы можем спокойно использовать
готовые наборы команд в разных проектах.
кодогенерация может быть поставлена на поток с помощью .proto классов
- в реальности все классы достаточно удобно писались ручками. Не
доверяю я автоматам)
package flashfight.game.messages
{
import flash.net.registerClassAlias;
import flashfight.game.messages.input.*;
import flashfight.game.messages.output.*;
import flashfight.game.messages.inner.*;
/**
* Функция регистрации удалённых классов.
*/
public function registerMessagesAlias():void
{
//input Message
registerClassAlias("1", GameStatusMessage);
registerClassAlias("2", CreateGameMessage);
registerClassAlias("3", MoveCharacterMessage);
registerClassAlias("4", CharacterMessage);
registerClassAlias("5", ChangeCharacterMessage);
registerClassAlias("6", GetCharacterMessage);
//output Message
//inner Message
}
}
По мне выглядит удобнее когда именно ивенты..
да и многим программистам думаю тоже, взять к примеру доку по классу
Sprite там описаны методы, свойства и ивенты.
думаю врятли найдется человек который бы писал так:
(this.sprite["startDrag"] as Function).apply(this.sprite);
Да и вообще суть не в этом
я говорю что надо написать костяк, а рутиной вроде генерации
_монструозных _ но задокументированных и понятных каждому классов
пусть занимается скрипт.
1. Не будет работать Find Reference
2. Есть риск получить исключение.
3. Всё равно для команд придётся создавать тучу монструозных классов.
switch (event.code) {
case 1001:
break;
case 1002:
break;
case 1003
break;
...
case 1567:
break;
}
1-е предложение Дениса
>Тут хорошо подходит паттерн Команда.
2. каким образом регистрировать id команд
варианты:
>Использовать в протоколе имена (вместо id) команд и вызывать как методы.
>Константы выносятся в отдельный класс, от него наследуется этот класс.
Класс с константами называю обычно что-то вроде DataFormat и он
содержит все именования узлов XML, атрибутов и стандартных значений. И
от него наследуются и другие классы, активно использующие формат.
>Командному процессору конечно же нужна таблица "соответствий" между
ключами и выполняемыми командами, путей реализации этой таблицы есть
множество. Денис хранит ее в xml, вы делаете динамическую
регистрацию
в рантайме, кто-то пишет портянки свитч-кейсов.
мой вариант : на каждую комманду - отдельный класс - реализующий
интерфейcный метод execute на стороне клиента - для входящих комманд
- метод execute на стороне сервера для исходящих.
регистрация - в registerClassAlias. Способ подходит как для AMF так и
для protoBuf. методы являются мостами для связки моделей данных между
серверной и клиентской моделью.
Автоматизация создания классов комманд (сообщений): в protoBuf классы
генерятся для сервера и клиента на основе .ptroto файлов
Для AMF тоже существуют скрипты автогенерации: например java <-> AS3
для graniteDS.
300 - 400 классов комманд - не так уж и много для большого проекта.
Если использовать "голый" xml в качестве транспортного протокола
необходим метод сериализации входящего xml в класс команды - в этом
случае, скорей всего можно по-другому организовать - если не нравится
так:
xml -> parser по id -> создание кастомного класса команды -> вызов
execute.
Тут есть два недостатока:
1) идентификация по строке, числовой идентификатор предпочтительней
для серилизации и вообще сложной системы
2) идентификатор является именем функции, то есть комманда, некая
инструкция, требует от исполнителя того, что к ней не относится, как
например, чтобы копать, не обязательно иметь фамилию Копалкин.
Это типичный пример из AS2, на нем вроде еще пишут.
блин я говорю НЕ ВАЖНО как реализовать выборку соответствия
обработчика к бинарным данным пришедшим с сокета
важно чтобы это делалось АВТОМАТИЧЕСКИ
1 одна оснавная дока
2 автосгенерированный клиентский и серверный код который на 100%
соответствует доке
а для оптимизации и скорости куча способов
например зачем передавать по бинарному сокету строку - имя команды
mySuperPuperCommand - 19байт
когда если комманд до 256 - передавать можно только один байт , если
комманд до 65536 - два байта
а названия и описания команд существуют только в доке и в
АВТОМАТИЧЕСКИ сгенерированном клиентском и серверном коде
еще про сложные типы данных - это тоже очень важно делать
автоматически - чтобы избежать ошибок
Ну замечательно, только эта самая автоматика не нужна.
возможно, в случаях с мелким количеством комманд в протоколе
и когда с протоколом работают только 2 человека, один со стороны
серверной части другой со стороны клиентской
всю эту автоматику написать можно хоть на АИРе если ничего другого под
рукой нету
плюсы есть
+сомнительный автокомплит и документация
+очень гибкий протокол, команды добавляются в 3 клика
+возможность работы неограниченно большой комманде с протоколом
+возможно реализовать любой архитектурный паттерн, придумать любой протокол
+если пойти ООП-шными более монстроподобными методами, все более гибкое,
этот протокол потом можно обвесить проксиками, повесить не только
на бинарный сокет, на хттп заросы на rtmp и тд..
минусы тоже
- только эта самая автоматика не нужна.
Илья намекал на дофига комманд.. решать ему..
фигли спорим я предложил вариант...