ActionScript: самоанализ уровня пакета? Или какая-то другая подключаемая схема загрузки?

Я пишу некоторую восхитительную бизнес-логику, и я пришел к такой ситуации:

Есть куча правил (ruleA, ruleBи т. д.), которые следуют стандартному шаблону. Я создал Rule интерфейс, и реализовал его в RuleA, RuleB, и так далее.

Так что теперь мне просто нужен способ загрузить их.

Прямо сейчас я использую карту:

var rules:Object = {
    ruleA: new RuleA(),
    ruleB: new RuleB(),
   ...
};

Тогда называя это так:

function doStuff(whichRule:String, someData:Object):* {
    return rules[whichRule].applyTo(someData);
}

Теперь правила следуют стандартной схеме именования, и все они являются частью одного пакета (foo.rules)... Есть ли способ загрузить правила, не сохраняя их в каком-то списке?

Спасибо!

Изменить: Чтобы уточнить, хотел бы обнаружить возможные правила во время выполнения, поэтому мне не нужно вести список правил. Например:

function loadRule(name:String):Rule {
    import foo.rules;
    var rule:Class = foo.rules[name];
    return new rule();
}

За исключением, конечно, я не могу индексировать в foo.rules Пространство имен... Но это то, что я хотел бы сделать.

5 ответов

Решение

Вы можете получить ссылку на класс из строки с помощью flash.utils.getDefinitionByName(className);

Например

def getRule(someValue: String) : Class{
    return getDefinitionByName("mybusiness.rules.Rule" + someValue);
}

В приведенном выше примере вы возвращаете класс, но вы также можете создать его экземпляр и вернуть объект.

Однако обратите внимание, что это будет работать, только если класс, идентифицируемый по имени класса, скомпилирован в ваш swf. Если нет в другом месте вашего кода, вы ссылаетесь на этот класс, иначе он не будет скомпилирован. Обычно это достигается созданием ссылок в каком-то другом фрагменте кода, иначе ваша система сборки может передать это компилятору.

Обратите внимание, что функции являются объектами первого класса в AS3, поэтому, в зависимости от вашего варианта использования, вы можете определить каждое правило как функцию в классе Rule и передать это:

def getRule(someValue: String) : Function{
    return new Rule()["theRuleName"];
}

Это зависит от того, сколько логики вы бы хотели в них включить, и сколько общего кода существует между этими правилами, конечно.

Мне жаль так говорить, но то, что вы хотите сделать, это simply impossible... речь идет не столько о самоанализе на уровне пакета... если бы был какой-то способ, это все равно было бы невозможно...

актуальная проблема:

все компиляторы ActionScript всегда только компилируют основной класс и зависимости... таким образом, если ваши реализации Rule никогда нигде не упоминаются, они не будут скомпилированы в результирующий swf... следовательно, они вообще не будут доступны во время выполнения...

самое близкое к тому, что вы хотите сделать, это, вероятно, написать сценарий сборки, который будет проходить через ваши пакеты и, следуя некоторому правилу, зарегистрировать классы с использованием некоторого автоматически сгенерированного кода... по крайней мере, вам нужно, это литерал Array., содержащий все классы

[Rule1, Rule2,...RuleN]

так просто... полагаясь на тот факт, что все правила находятся в одном пакете (что я считаю ужасным ограничением), вы можете использовать getDefinitionByName чтобы получить правильный класс...

ИМХО, однако, кроме того, что это нелегко реализовать, этот подход также плохой стиль... он довольно хакерский и накладывает слишком много...

картографический подход - почти лучшее, что вы можете получить... используя карту, классы появляются в вашем коде и, таким образом, компилируются, и это чистый способ поиска... кроме того, у вас больше влияния...

Вы можете создать правила, как это:

class NameIsRule implements IRule {
    private var _name:String;
    public function NameIsRule(name:String) {
        this._name = name;
    }
    public function applyTo(target:Object):* {
        return target.hasOwnProperty("name") && (target.name == this._name)
    }
}

а затем есть

rules = {
    isCalledJim : new NameIsRule("Jim"),
    isCalledJohn : new NameIsRule("John")
}

(глупый пример, но я надеюсь, что это иллюстрирует суть)

и вы могли бы захотеть обернуть это в класс, чтобы быть чище...

package {
    public class RuleMap {
        private var _rules:Object = {}
        public function RuleMap(init:Object = null) {
            for (var name:String in init) 
                this.addRule(name, init[name]);
        }
        public function addRule(id:String, rule:IRule):IRule {
            if (this.ruleExists(id))
                throw new Error("duplicate rule for id " + id);
            if (rule == nul)
                throw new ArgumentError("invalid value null for parameter rule");
            this._rules[id] = rule;
            return rule;
        }
        public function applyRule(id:String, target:Object):* {
            return this.getRule(id).applyTo(target);
        }
        public function getRule(id:String):IRule {
            if (this.ruleExists(id))
                return this._rules[id];
            else 
                throw new Error("no rule for id " + id);
        }
        public function ruleExists(id:String):Boolean {
            return this._rules.hasOwnProperty(id);
        }
    }
}

это немного более многословно (ну, вы всегда можете передать объект конструктору), но это намного безопаснее, дает более разумные значения и быстрее, так как AVM2 быстрее при выполнении строго типизированного кода (в отличие от динамического код, вы на самом деле используете интерфейс... объявлять интерфейс совершенно бессмысленно, если ни один из вашего кода не полагается на него) ...

Кроме того, вы должны потратить время на создание констант для правил, вместо того, чтобы иметь тонны строковых литералов во всем коде... это поможет против опечаток и т. д....

при работе с запечатанными классами в AS3, как и у вас, нетипизированное кодирование не дает никаких преимуществ, потому что оно имеет смысл только с языками типа ducktyped... а AS3 нет... в строгих языках, соблюдайте строгость, и компилятор будет проделать большую работу за вас и сэкономить много времени на отладку...

Мне нравится идея, лежащая в основе Правил (хорошая, чистая и гибкая), но, имхо, вам следует быть более точным, чем ленивым в этой точке... я бы подумал, что это нечто в основе вашего приложения... так пусть он будет твердым...;)

Greetz

back2dos

Это похоже на хороший вариант реализации Factory Patteren для получения нужного вам объекта. Что-то вроде:

public class RuleFactory
{
   public function create(ruleID : String) : IRule
   {
      switch (ruleID)
      {
         case "ruleA":
            new RuleA();
            break;
         case "ruleB":
            new RuleB();
            break;
      }
   }

}

тогда вы называете это с чем-то вроде

function doStuff(whichRule:String, someData:Object):* 
{
   var ruleFactory : RuleFactory = new RuleFactory();
   var rule : IRule = ruleFactory.create(whichRule);

   return rule.applyTo(someData);
}

Кто-то может сказать, что это излишне, но это, вероятно, тот подход, который я бы выбрал, так как это краткая и связная абстракция, которая имеет смысл для большинства разработчиков.

Вы пытались написать анализатор текста в правила и простой механизм правил вместо отдельных классов правил? Я не видел движок правил, написанный на Actionscript (за исключением проприетарного и несколько грубого порта Ruleby, который я однажды создал вместе), но придумать красивый синтаксис сложнее, чем придумать наивную реализацию одного.

Вот несколько идей:

  • иметь одно настраиваемое правило класса, которое настраивается через внешний XML/JSON или другой такой формат, который будет определять его свойства.

  • напишите свои правила в javascript и используйте ExternalInterface.

  • Упакуйте ваши правила в SWF как модули и загружайте их динамически.

Другие вопросы по тегам