Haxe: шаблон привязки с абстрактными полями доступа - PullRequest
1 голос
/ 14 октября 2019

Я хотел бы создать оболочку для реализации простого шаблона привязки данных - хотя некоторые данные были изменены, все зарегистрированные обработчики получают уведомление. Я начал с этого (для js target):

class Main {
    public static function main() {
        var target = new Some();
        var binding = new Bindable(target);
        binding.one = 5;
        // binding.two = 0.12; // intentionally unset field
        binding.three = []; // wrong type
        binding.four = 'str'; // no such field in wrapped class
        trace(binding.one, binding.two, binding.three, binding.four, binding.five);
        // outputs: 5, null, [], str, null
        trace(target.one, target.two, target.three);
        // outputs: 5, null, []
    }
}

class Some {
    public var one:Int;
    public var two:Float;
    public var three:Bool;
    public function new() {}
}

abstract Bindable<TClass>(TClass) {
    public inline function new(source) { this = source; }
    @:op(a.b) public function setField<T>(name:String, value:T) {
        Reflect.setField(this, name, value);
        // TODO notify handlers
        return value;
    }
    @:op(a.b) public function getField<T>(name:String):T {
        return cast Reflect.field(this, name);
    }
}

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

Можно ли исправить мое решение или мне лучше перейти к макросам?

Ответы [ 2 ]

1 голос
/ 17 октября 2019

Я почти предложил здесь открыть вопрос по этой проблеме. Потому что некоторое время назад для тезисов была доступна мета @: followWithAbstracts, которую можно (или, возможно, было) использовать для пересылки полей и одновременного вызова @: op (ab). Но это на самом деле не нужно, Haxe уже достаточно мощный.

abstract Binding<TClass>(TClass) {
    public function new(source:TClass) { this = source; }
    @:op(a.b) public function setField<T>(name:String, value:T) {
        Reflect.setField(this, name, value);
        // TODO notify handlers
        trace("set: $name -> $value");
        return value;
    }
    @:op(a.b) public function getField<T>(name:String):T {
        trace("get: $name");
        return cast Reflect.field(this, name);
    }
}

@:forward
@:multiType
abstract Bindable<TClass>(TClass) {
    public function new(source:TClass);
    @:to function to(t:TClass) return new Binding(t);
}

Мы используем здесь мультирежимный абстракция для пересылки полей, но разрешенный тип на самом деле является регулярным абстрактным. По сути, у вас есть работа завершения и вызов @: op (ab) одновременно.

1 голос
/ 14 октября 2019

Вам нужно @: переслать мета в вашем резюме. Тем не менее, это не приведет к автоматическому завершению работы, если вы не удалите @: op (AB), потому что он затеняет перенаправленные поля.

РЕДАКТИРОВАТЬ: кажется, что затенение произошло в первый раз, когда я добавил @: forward к вашему резюме, потомавтозаполнение работало просто отлично.

...