|
|
« Предыдущая тема | Следующая тема » |
Опции темы | Опции просмотра |
|
|
|||||
Как улучшить класс APIConnection. Вопрос по обработке полученных данных.
Недавно в своем блоге писал о библиотеке для роботы с Вконтакте API. В библиотеке единственным обязательным классом служит APIConnection, который занимается контролем над потоком вызовов, а сами вызовы это VkontakteCall с самим сформированым запросом и обработчиками этого запроса. На экземпляры класса вешаются события успешной загрузки и ошибки в ответе а так же ошибки загрузки. Так вот товарищ cleptoman написал, что создания отдельного кола - это не то что совсем бы хотелось от библиотеки и лучше бы если был класс который рулит запросами и диспатчит события . Идея отличная только вот не могу остановиться на реализации.
Переписал APIConnection и теперь он выглядит вот так: Смотрите следующий пост ( есть ограничения форума на количество символов в посте, пришлось даже удалить даже часть вода в классе ). APIConnection теперь не наследует класс EventDispatcher, а реализует интерфейс IEventDispatcher. Сделано было для того что бы можно было использовать привычные addEventListener() и removeEventListener() но с другой реализацией. Теперь у каждого кола есть уникальный тип события который есть же сигом запроса это кола. События вешаются как обычно, но тип события же не имеет ни какого значения так как формируеться совсем другой и нужен скорее для ясности происходящего. Событие вешается только после того как добавили в поток вызовов кол. Много думал может просто сделать обычные колбеки и не заморачиватся с событиями. Или же вешать события на класс сколько будет удобно а в самом обработчике события проверять от какого вызова метода пришол ответ и потом выполнять действия. Или же отставить все как есть и нечего не изменять. Хотелось бы услышать какие-нить мнения по этому поводу. Хочеться сделать либу максимально удобной в использовании. Последний раз редактировалось VitaliyKrivtsov; 24.03.2011 в 02:52. |
|
|||||
package phantom.api.vkontakte { public class APIConnection implements IEventDispatcher { private var dispatcher:EventDispatcher; // -- // public static var httpMethod: String = "POST"; //public static const XML :String = "XML"; //spublic static const JSON :String = "JSON"; public static const POST :String = "POST"; public static const GET :String = "GET"; private var wrapper:Object; private var flashVars:Object; // -- // private static var instance:APIConnection; // -- // private static var _apiUrl :String = "http://api.vkontakte.ru/api.php"; private static var _format :String = "XML"; private static var _version :String = "3.0"; // -- // private static var _apiId :String; private static var _viewerId :String; private static var _userId :String; private static var _secret :String; private static var _sid :String; private static var _authKey :String; private static var _group :String; private static var _lcName :String; // -- // private static var _domain :String; private static var _scale :int; private static var _width :int; private static var _height :int; private static var _swfUrl :String; private static var _debug :int; // -- // private static var _test :Boolean; private static var _isAppUser :Boolean; private static var _viewerType :int; private static var _settings :int; private static var _language :int; private static var _delay:int = 300; //private var params:Array = new Array()/* of Parameter */; private var commandQueues:Array = new Array()/* of VkontakteCall */; private var current:int = 0; private var timer:Timer; // -- // //private var requests:Vector.<URLLoader> = new Vector.<URLLoader>(); private var requests:Array = new Array()/* of URLLoader */; private var listeners:Dictionary = new Dictionary()/* of Function */; // -- // private var loaders:Dictionary = new Dictionary()/* of URLLoader */; public function APIConnection() { dispatcher = new EventDispatcher( this ); } public function init( params:Object ):void { timer = new Timer( _delay ); timer.addEventListener( TimerEvent.TIMER, timerHandler ); if ( params.wrapper ) wrapper = Object(params.wrapper); // -- // if ( params.auth_key ){ _viewerType = new int( params.viewer_type ); _settings = new int( params.api_settings ); _isAppUser = new Boolean( params.is_app_user ); _lcName = new String(params.lc_name); _userId = new String(params.user_id); _group = new String(params.group_id); _authKey = new String(params.auth_key); } // -- // if ( params.test ) _test = new Boolean(params.test); if ( params.api_url ) _apiUrl = new String(params.api_url); if ( params.api_id ) _apiId = new String(params.api_id); if ( params.viewer_id ) _viewerId = new String(params.viewer_id); if ( params.secret ) _secret = new String(params.secret); if ( params.version ) _version = new String(params.version) else _version = new String("3.0"); if ( params.sid ) _sid = new String(params.sid); if ( params.format ) _format = new String(params.format); // -- // } public function addEventListener( type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false ):void { var loader:URLLoader = requests[requests.length - 1];/* requests as Vector.<URLLoader> */; // -- // if ( !loaders[loader].flag/* loaders[loader] as Object */) return; // -- // var str:String = loaders[loader].type;/* type события, для каждого запроса формируется уникальное имя события по его sig*/ listeners[listener] = str;/* запоминаем type события */ loaders[loader].flag = false; // -- // dispatcher.addEventListener( str, listener, useCapture, priority, useWeakReference ); } public function removeEventListener( type:String, listener:Function, useCapture:Boolean = false ):void { var type:String = listeners[listener]; dispatcher.removeEventListener( type, listener, useCapture ); // -- // delete listeners[listener]; // -- // } public function dispatchEvent( event:Event ):Boolean { return dispatcher.dispatchEvent( event ); } public function hasEventListener( type:String ):Boolean { return dispatcher.hasEventListener( type ); } public function willTrigger( type:String ):Boolean { return dispatcher.willTrigger( type ); } ////////////////////////////////////////////////////////////////////// // // public methods // ////////////////////////////////////////////////////////////////////// public function call( vkcall:*/*URLRequest else VkontakteCall*/ ):void { if ( vkcall is URLRequest ) { var loader:URLLoader = new URLLoader(); loader.addEventListener( Event.COMPLETE, completeHandler ); loader.addEventListener( IOErrorEvent.IO_ERROR, ioErrorHandler ); // -- // requests.push( loader ); // -- // loaders[loader] = {flag:true, request:vkcall, method:vkcall.data.method, type:vkcall.data.sig}; // -- // commandQueues.push( loader ); } else if ( vkcall is VkontakteCall ) { commandQueues.push( vkcall ); } // -- // if ( !timer.running ) { timerHandler( ); timer.start( ); timer.addEventListener( TimerEvent.TIMER, timerHandler ); } } private function completeHandler( e:Event ):void { var loader:URLLoader = URLLoader(e.target); // -- // var object:Object = loaders[loader]; // -- // var urlRequest:URLRequest = object.request; var data:String = String(e.target.data); if ( urlRequest.data.format == "XML" ) { var fxml:XML = XML( data ); //trace( fxml ); //if ( fxml.name() == "response" ) xmlResponseHandler( fxml ); //else if ( fxml.name() == "error" ) xmlErrorHandler( data, fxml ); } else if ( urlRequest.data.format == "JSON" ) { var fjson:Object = JSON.decode( data ); //if ( fjson.response != undefined ) jsonResponseHandler( fjson ); //else if ( fjson.error != undefined ) jsonErrorHandler( data, fjson ); } // -- // dispatchEvent( new VKResponseEvent( object.type, this, data, object.method, false, false) ); // -- // object = null;/* обнуляем object */ delete loaders[loader];/* удаляем object из loaders, в противном случаи object не удалиться из памяти */ // -- // loader.removeEventListener( Event.COMPLETE, completeHandler ); } private function ioErrorHandler( e:IOErrorEvent ):void { dispatchEvent( new IOErrorEvent(e.type, false, false) ); } public function close( ):void { timer.stop( ); // -- // for ( var i:int = 0; i < commandQueues.length; i++ ) { var vkcall:VkontakteCall = commandQueues[i] as VkontakteCall; vkcall.close( ); } // -- // commandQueues.length = 0; current = 0; } private function timerHandler( e:TimerEvent = null ):void { if ( current != commandQueues.length ) { /* */ if ( commandQueues[current] is URLLoader ) { var loader:URLLoader = commandQueues[current]; loader.load( loaders[loader].request/*as URLRequest*/ ); } else { var vkontakteCall:VkontakteCall = commandQueues[current]; vkontakteCall.load( ); } // -- // current++; // -- // } else { timer.stop( ); commandQueues.length = 0; current = 0; timer.removeEventListener( TimerEvent.TIMER, timerHandler ); } } ////////////////////////////////////////////////////////////////////// // // public static functions // /////////////////////////////////////////////////////////////////////// /** * * @return */ public static function getInstance( ):APIConnection { if ( !instance ) { instance = new APIConnection() }; return instance; } /** * * @param parameters * @return URLRequest */ public static function req( parameters:Vector.<Parameter> ):URLRequest { // -- // var params:Array = []; for ( var j:int = 0; j < parameters.length; j++ ) { params.push( parameters[j] as Parameter ); } // -- // params.push( new Parameter("api_id", _apiId) ); params.push( new Parameter("format", _format) ); params.push( new Parameter("v", _version) ); if ( _test ) params.push( new Parameter("test_mode", "1") ); // -- // params.sortOn( "name" ); // -- // //params.push( new Parameter("sig", getSig(params)) ); params.push( new Parameter("sig", MD5.hash(new String( _viewerId + params.join("") + _secret)) ) ); //; if( _version != "2.0" ) params.push( new Parameter("sid", _sid) ); // -- // var urlRequest:URLRequest = new URLRequest( ); urlRequest.url = _apiUrl; urlRequest.method = httpMethod; var urlVariables:URLVariables = new URLVariables( ); // -- // for ( var i:int = 0; i < params.length; i++ ){ urlVariables[params[i].name] = params[i].value; } // -- // urlRequest.data = urlVariables; //--// params.length = 0; params = null; // -- // return urlRequest; } } } Неужели вот это всем все равно? Как бы не только для себя делаю. |
|
|||||
Регистрация: Nov 2010
Сообщений: 497
|
Ну могу покритиковать. Берем пример из блога и смотрим, что приходится писать при каждом вызове:
/*>>*/var vkcall:VkontakteCall = new VkontakteCall(); /*<<*/ var fields:Array = [...]; vkcall./*>>*/call(/*<<*/ Users.getProfiles( [APIConnection.viewerId], fields /*>>*/) as URLRequest /*<<*/); /*>>*/vkcall.addEventListener( VKResponseEvent.RESPONSE, /*<<*/responseHandler ); /*>>*/vkcall.addEventListener( VKErrorEvent.ERROR, /*<<*/ errorHandler ); Пример того, как это могло бы быть: APIConection.users.getProfiles([UserField.NAME, UserField.NICKNAME, UserField.UID, UserField.PHOTO_BIG], usersReceived, errorHandler); function usersReceived(users : Array /* or Object */) { for each (var o : Object in users) trace(o[UserField.NAME] + " " + o[UserField.NICKNAME] + " " + o[UserField.UID] + o[UserField.PHOTO_BIG]); } Итого - ровно одна строчка на запрос вместо 5. И в обработчике результата работа идет не с абстрактными row (или что там еще есть) а со вполне конкретными пользователями, которых мы запрашивали (или не запрашивали). По поводу событий. Скажите, а как вы собираетесь обрабатывать события в обработчиках? Точно хочется получать весь спам от "неизвестных" запросов? Потому что для "своих" запросов обработчики то известны и их можно коллбэком передать. Так как методов много, сразу все писать будет долго. Я бы делал удобное (именно удобное для использования в количестве 20-30 раз в проекте) API с минимумом удобных методов - полным разбором результатов, говорящими параметрами и т.п. А затем все это при необходимости расширял (практически все затем делается достаточно просто). Собственно, именно так и делаю |
Часовой пояс GMT +4, время: 20:45. |
|
« Предыдущая тема | Следующая тема » |
|
|