Структура данных FluentList
Продолжаю эксперимены начатые в
Реализация Fluent interfaces
FDProject:fluentInterface_v2.zip
Класс FluentList
package ru.k0t0vich.fluent { import flash.utils.getQualifiedClassName; import ru.k0t0vich.fluent.conditions.Condition; import ru.k0t0vich.fluent.parsers.FluentStringParser; import ru.k0t0vich.fluent.parsers.FluentXMLParser; /** * Класс реализующий структуру данных: "Естественный список." (с)k0t0vich (smile:)) * Представляет собой список элементов с методами выборки и сортировки организованными на "естественном языке". * Позволяет: выбирать элементы удовлетворяющиее условиям, производить групповые операции над элементами выборки, * сортировать выборки по полям элементов, добавлять/удалять элементы из списка. * * TODO: объединение/ разность списков. * Выражение для выборки должны быть представлены в ДНФ(дизъюнктивно нормальная форма). * @author k0t0vich */ public class FluentList { private var unitList:Array; private var dnfArray:Array = []; private function get currConjunctionArray():Array { return dnfArray[dnfArray.length - 1] as Array; } public function FluentList($unitList:Array=null) { if ($unitList) unitList = $unitList; else unitList = []; // начинаем дизъюнкцию clearConditions(); } /** * Синоним join() * Добавить блок конъюнктов. * Дизъюнктивно объеденить с предыдущим блоком условий (опрация ИЛИ) * @return */ public function or():FluentList { dnfArray.push([]); return this; } /** * Добавить в текущий конъюнкт условие (операция И) * Валидность условия проверяется в рантайме. * @param $field поле элемента списка * @param $condition условие (==,!=,<,>,<=,>=) * @param $value значение * @return */ public function where($field:String, $condition:String, $value:*):FluentList { //trace("FluentList.where > $field : " + $field + ", $condition : " + $condition + ", $value : " + $value); currConjunctionArray.push(new Condition($field, $condition, $value)); return this; } /** * Синоним or() * Добавить блок конъюнктов. * Дизъюнктивно объеденить с предыдущим блоком условий (опрация ИЛИ) * @return */ public function join():FluentList { return or(); } /** * Выбрать элементы удовлетворяюшие ДНФ * @return */ public function group():FluentList { var retFluentList:FluentList = new FluentList(); var len:int = unitList.length; for (var i:int = 0; i < len; i++) { var unit:* = unitList[i]; if (valueConditionsWithUnit(unit)) { retFluentList.push(unit); } } clearConditions(); return retFluentList; } /** * Очистить ДНФ * @return */ private function clearConditions():FluentList { dnfArray = []; return or(); } /** * Разбираем ДНФ для юнита * @param unit * @return */ private function valueConditionsWithUnit(unit:*):Boolean { var dnfLen:int = dnfArray.length; var dnfRet:Boolean = false; for (var i:int = 0; i < dnfLen; i++) { var conjArray:Array = dnfArray[i] as Array; var conjLen:int = conjArray.length; var conjRet:Boolean = true; for (var j:int = 0; j < conjLen; j++) { var condition:Condition = conjArray[j] as Condition; if (!condition.valueCondition(unit)) { conjRet = false; //досрочный выход из конъюнкта break; } } dnfRet = dnfRet || conjRet; if (dnfRet) return true; // досрочный выход из дизъюнкта } return false; } /** * Выполнить у юнитов удовлетворяющих ДНФ ф-цию * @param func : имя ф-ции * @param args : аргументы */ public function call(funcName:String,args:Array):FluentList { var len:int = unitList.length; for (var i:int = 0; i < len; i++) { var unit:* = unitList[i]; if (valueConditionsWithUnit(unit)) { // действие над каждым отфильтрованным элементом try { var func:Function = unit[funcName]; } catch (e:Error) { throw new Error("'"+funcName+"'"+ " is not member of "+ getQualifiedClassName(unit)+"! Standart error: "+e); } func.apply(unit, args); } } return clearConditions(); } /** * Выполнить ф-цию над юнитами удовлетворяющими ДНФ * @param func : ф-ция вида func(unit:*,args) * @param args : аргументы */ public function execute(func:Function,...args):FluentList { var len:int = unitList.length; for (var i:int = 0; i < len; i++) { var unit:* = unitList[i]; if (valueConditionsWithUnit(unit)) { func(unit, args); } } return clearConditions(); } /** * Распарсить XML сценария * @param xml * @return */ public function parseXML(xml:XML):FluentList { return FluentXMLParser.parse(this,xml); } /** * Распарсить Script сценария * @param xml * @return */ public function parseString(str:String):FluentList { return FluentStringParser.parse(this,str); } /** * Композиционные методы для массива * TODO: добавить остальные */ public function push(unit:*):FluentList { unitList.push(unit); return this; } public function pop():* { return unitList.pop(); } public function get length():int { return unitList.length; } public function toString():String { return "[FluentList" + String(unitList) + " ]"; } public function sortOn(names:*,options:*=0):FluentList { unitList.sortOn(names, options); return group(); } } }
package { import flash.display.Sprite; import flash.events.Event; import ru.k0t0vich.fluent.conditions.Condition; import ru.k0t0vich.fluent.FluentList; import ru.k0t0vich.fluent.parsers.FluentStringParser; import ru.k0t0vich.units.Unit; /** * Тестоый пример * @author k0t0vich */ public class Main extends Sprite { public function Main():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // entry point //Создаем список юнитов var enemies:FluentList = new FluentList(); // Заполняем for (var i:int = 0; i < 10; i++) { var unit:Unit = new Unit(i,-i*10); enemies.push(unit); } // весь список trace("TOTAL: " + enemies); // выполняем // Для всех юнитов с Z>-80 и Z<-50 // c уровнем не меньше 5 или для юнитов с уровнем 1 // отсортировать по Z и стрелять пушками типа 1 частотой 10. trace("\r______тест AS3 выражения_________ "); var tmp1: FluentList = enemies .where(Unit.Z, Condition.GT, -80) .where(Unit.Z, Condition.LT, -50) .where(Unit.LEVEL, Condition.GE,5) .or() .where("level", "==", 1) .sortOn("z",Array.NUMERIC) .call(Unit.DO_SHOOT, [1, 10]); trace("tmp1 : " + tmp1); trace("\r______тест XML парсера_________ "); //тест парсера. var xml:XML = <data> <where field="z" condition=">" value="-80" /> <where field="z" condition="<" value="-50" /> <where field="level" condition=">=" value="5" /> <or/> <where field="level" condition="==" value="1" /> <sort field="z" by="numeric"/> <call func="doShoot" args="1,10" /> </data> var tmp2:FluentList = enemies.parseXML(xml); trace("tmp2 : " + tmp2); trace("\r______тест Script парсера_________ "); var str:String ='where z > -80; where z < -50; where level >= 5; or; where("level", "==", 1); sortOn z,numeric ; \r call doShoot 1,10'; var tmp3:FluentList = enemies.parseString(str); trace("tmp3 : " + tmp3); return; } } }
- выборка товаров из магазина по нужным фильтрам
- z - сортировка в изо-мире
- загружаемый сценарий действий компьютерного оппонента в зависимости от уровня.
Всего комментариев 8
Комментарии
![]() ![]() |
|
Это кстати отличная идея ))
И не менее отличная реализация )) |
![]() ![]() |
|
![]() ![]() |
|
2mayakwd
не совсем моки, скорее старый добрый sql для выборки данных несколько условий, это то-же самое что or или and. аналог в ДНФ можно представить любое выражение, как вам изместно) само выражение вычисляется только при call, group итп. Набор where только создают списки кондишинов. Да и парсеры выглядят проще. Если говорить про парсеры строк, то вообще хороший декларатив получается.. или ты имеешь ввиду ? Цитата:
where z==100 && level<15;
Это всё конечно не OCAML.. так баловство. Мне именно идея с возвратом себя же или выборки своего же типа понравилась. |
|
Обновил(-а) Котяра 02.11.2010 в 01:06
|
![]() ![]() |
|
старый добрый sql старается комбинировать условия, а не выполнять их последовательно. тебе видимо в голову ударила тормознутость jquary =)
а ваще ты XMLList изобрёл =) |
![]() ![]() |
|
Оказывается я "изобрел" LINQ)
|
![]() ![]() |
|
Linq actionscript style!
|
Последние записи от Котяра
- Страх и ненависть в Нью-Дели или сборка мультипака для arm7 и x86 c Adobe AIR 14 в FB (16.06.2014)
- Нативный EventDispatcher в старлинге (27.11.2013)
- Нужны ошибки компиляции при создании экземпляра синглетона извне? Запросто! (13.09.2013)
- ARP - новый формат упаковки ресурсов (07.02.2013)
- DropShadowFilter и GlowFilter в Starling (16.01.2013)