Реализация Fluent interfaces
Сегодня товарищ прислал ссылку на Fluent interfaces.
Вначале я не вкурил, но потом почитал еще и загорелся реализовать нечто подобное на AS3.
тестовый класс:
package { import flash.display.Sprite; import flash.events.Event; import ru.k0t0vich.fluent.Unit; import ru.k0t0vich.fluent.UnitList; /** * Тестоый пример * @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:UnitList = new UnitList(); // Заполняем for (var i:int = 0; i < 10; i++) { var unit:Unit = new Unit(i,i*10); enemies.push(unit); } // весь список trace("TOTAL: " + enemies); // выполняем // все враги выше 2 уровня и высотой меньше 50 стреляют оружием 1 типа с частотой 1. enemies.isLevelGreater(2).isZLower(50).doShoot(1, 10); // выделяем группу врагов старше 8 уровня var bigEnemies:UnitList = enemies.isLevelGreater(8); // список больших врагов trace(" Big: " +bigEnemies); } } }
Цитата:
TOTAL: [Unit level:0 z:0],[Unit level:1 z:10],[Unit level:2 z:20],[Unit level:3 z:30],[Unit level:4 z:40],[Unit level:5 z:50],[Unit level:6 z:60],[Unit level:7 z:70],[Unit level:8 z:80],[Unit level:9 z:90]
Unit.doShoot > level:3 z:30
Unit.doShoot > level:4 z:40
Big: [Unit level:9 z:90]
Unit.doShoot > level:3 z:30
Unit.doShoot > level:4 z:40
Big: [Unit level:9 z:90]
package ru.k0t0vich.fluent { /** * * @author k0t0vich */ public class UnitList { private var unitList:Array; public function UnitList($unitList:Array=null) { if ($unitList) unitList = $unitList; else unitList = []; } /** * * Конкретные методы сортировки */ /** * @param z * @return */ public function isZLower(z:int):UnitList { var retUnitList:UnitList = new UnitList(); var len:int = unitList.length; for (var i:int = 0; i < len; i++) { var unit:IUnit = unitList[i]; /** * выражение для добавления в список */ if (unit.z < z) retUnitList.push(unit) } return retUnitList; } public function isLevelGreater(level:int):UnitList { var retUnitList:UnitList = new UnitList(); var len:int = unitList.length; for (var i:int = 0; i < len; i++) { var unit:IUnit = unitList[i]; /** * выражение для добавления в список */ if (unit.level > level) retUnitList.push(unit) } return retUnitList; } /** * Конкретный метод - окончание выражения * @param type * @param f */ public function doShoot(type:int,f:int):void { var len:int = unitList.length; for (var i:int = 0; i < len; i++) { var unit:IUnit = unitList[i]; unit.doShoot(type, f); } } /** * Композиционные методы для массива * TODO: добавить остальные */ public function push(unit:IUnit):UnitList { unitList.push(unit); return this; } public function pop(unit:IUnit):IUnit { return unitList.pop() as IUnit; } public function toString():String { return String(unitList); } } }
package ru.k0t0vich.fluent { import ru.k0t0vich.fluent.IUnit; /** * ... * @author k0t0vich */ public class Unit implements IUnit { private var _level:int; private var _z:int=100; public function Unit($level:int=1,$z:int=0) { level = $level; z = $z; } public function doShoot(type:int, f:int):void { trace("Unit.doShoot > level:"+ this.level+" z:"+z); } public function get level():int { return _level; } public function set level(value:int):void { _level = value; } public function get z():int { return _z; } public function set z(value:int):void { _z = value; } public function toString():String { return ("[Unit level:"+ this.level+" z:"+z+"]"); } } }
package ru.k0t0vich.fluent { /** * ... * @author k0t0vich */ public interface IUnit { function doShoot(type:int, f:int):void; function get z():int; function get level():int; } }
greater(field:String,value) lower(field:String,value) with(field:String,value) range(field:String,value1,value2) where(????), select(???)
но
выглядит покрасивше и не даёт гейм-дизайнеру лишних методов)
Использовать можно много где..
сейчас сразу пришло на ум: например зашивать логику уровней в отдельные подгружаемые swf.
Т.е. для каждого уровня есть некий класс CustomFluentScript расширяющий IFluentScript
конструктор:
и некий публичный метод
вызываемый в нужное время - а в нём уже описываем логику..
FDProject:
fluentInterface.zip
Всего комментариев 8
Комментарии
05.02.2010 21:29 | |
Да, прикольная штука, мне тоже понравилась - я так аналог E4X разборки XML в HaXe сделал. А еще планирую на такую структуру пересадить события (или точнее - сигналы) в AS3.
|
06.02.2010 23:42 | |
спасибо, очень интересно
|
08.02.2010 11:13 | |
Некоторое время спустя посмотрел критически на код)
что не нравится: 1) Создание "лишних" объектов UnitList при каждой сортировке и проход по всем юнитам в списке, например в isLevelGreater. думаю создать список фильтров и добавлять их при вызове сортирующих ф-ций, а в момент конкретного выполнения(doShoot) - применять их к объектам списка. для вывода списка ввести ф-цию выполнения select() или group() типа 2) нужны фильтры типа ИЛИ/НЕ/ИЛИ-НЕ/И-НЕ - сейчас только И. над реализацией думаю. что-то вроде: // для врагов больше 5 уровня //и высотой ниже 50 или для врагов с типом не равным // 1 и 2 вызвать ф-цию . enemies .or() .and() .where(Unit.LEVEL, ">", 5) .where(Unit.Z, "<", 50) .xor() .where(Unit.TYPE, "==", 1) .where("type", UnitList.EQ, 1) // альтернативный синтаксис записи .doShoot(1, 10); // Аналог: var len:int = enemies.length; for (var i:int = 0; i <len ; i++) { var enemy:IUnit = enemies[i]; if ((enemy.level > 5 && enemy.z < 50) || (!(enemy.type == 1) || !(enemy.type == 2) )) enemy.doShoot(1, 10); } // более естественный порядок выражения //(нет блоков, но выражение должно быть приведено к ДНФ (дизъюнкция конъюнкций) // здесь: (AB) || !C || !DE enemies // для всех врагов .where(UnitField.LEVEL, ">", 5) // где уровень больше 5 .where(UnitField.Z, "<", 50) // и z < 50 .or() // или .where(UnitField.TYPE, "!=", 1) // тип не равен 1 .or() // или .where(UnitField.TYPE, "!=", 2) // тип не равен 2 .where(UnitField.RANGE, "==", UnitRange.Captain)// и ранг равен капитану .doShoot(1, 10); // стрелять оружием 1 типа с частотой 10; продолжение следует.. |
|
Обновил(-а) Котяра 08.02.2010 в 13:46
|
08.02.2010 11:35 | |
Все гениальное просто. Интересная штука.
|
09.02.2010 10:09 | |
во первых where - должен возвращать this или как минимум UnitList, а не Boolean.( или я что-то недопонял)
во 2-х я думал использовать энумераторы, и может и буду, просто мне кажется что выглядит естественнее чем вообще схема такая - создаем массив массивов для ДНФ, or() создаёт следующую дизъюнкцию where(field,condition,value) добавляет в конъюнкцию выражение при выводе ( конечная ф-ция флюент выражения, например group()) проходимся по списку ВСЕХ юнитов и применяем к каждому последовательно выражения из ДНФ ( конечно с сокращением, по дизъюнктам и конъюнктам) В общем проще кодом показать.. сегодня как время будет чуток, сделаю. у меня еще вопрос возник - как лучше поступить с расширением класса UnitList ?- для потомка придётся переопределять тип всех флюент методов: public class CustomUnitList extends UnitList { override public function where(..):CustomUnitList { return super.where(...) as CustomUnitList } ... } } И еще, имеет ли смысл на вектора перевести? |
|
Обновил(-а) Котяра 09.02.2010 в 10:13
|
08.03.2023 12:12 | |
Последние записи от Котяра
- Страх и ненависть в Нью-Дели или сборка мультипака для 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)