Java: как сделать попроще?
Не нравится то, что будет много объектов класса Eval, которые по сути будут реализовать константу, но их все равно придется каждый раз проверять в update.Оверхед по цпу будет, но очень мизерный, порядка десятков наносекунд.
В итоге может получится не совсем быстро.
По памяти тоже это можно все оптимизировывать, но там оверхед типа 16 байт на один объект.
Я не думаю, что это все представляет какую-то проблему.
Может кто подскажет как попроще можно сделать?Я бы не делал стейтфул классы Eval, а просто сделал бы у них один метод
public float getValueAt(float msDelta);
Если ты хочешь все типа красиво без оверхедов, то делай Eval интерфейсом, и несколько его реализаций - ConstantEval, ArrayEval, ... .
Создай вспомогательный класс-аниматор, который будет реализовывать эту логику. Просто, удобно и единообразно.
public float getValueAt(float msDelta);Не подойдет. Я как обычно не все расписал, что надо - значение должно управляться меняться сразу после привязки (то есть у Eval надо будет добавить public void start т.е. выдаваемое значение должно зависеть не от системного времени, а от момента привязки и системного времени.
, чего то не нашел шаблон проектирования аниматор. Может у него есть альтернативное название?
А как еще вот такой вариант: сделать через reflection
class Eval
{
...
private Array<Eval> EvalList = new Array<Eval>;
private Object obj;
private String fieldName;
static add(Object obj, String fieldName, ..);
static void update(float msDelta); // пробегаем по всем объектам Eval и через reflection меняем значения у целевых атрибутов сторонних классов
}
A a = new A;
Eval.add(a, "posX", ..)
Насколько я понимаю в Java можно хранить ссыль только на объект/метод, а не на простой тип, поэтому в update каждый раз придется через reflection лазить и искать нужное поле у стороннего объекта?
class A
{
public float age;
public float weight;
}
class B
{
public float width;
public float height;
public A a1 = new A;
}
class Program
{
static void Main
{
var a= new A;
var b = new B;
var evaluator = new Evaluator;
evaluator.Bind=>a.age, v=>a.age=v, (v, context)=>v + 1);
evaluator.Bind=>b.a1.weight, v=>b.a1.weight=v, (v, context)=>v * 1.1);
for (var i = 0; i < 100; ++i)
{
evaluator.Update;
Console.WriteLine(b.a1.weight);
}
}
}
class Evaluator
{
List<Func<float, EvaluatorContext, float>> bindings = new List<Func<float, EvaluatorContext, float>>
void Bind(Func<float> getter, Func<float> setter, Func<float, EvaluatorContext, float> f)
{
bindings.Add(new Binding{getter = getter, setter = setter, f = f});
}
public void Update
{
var context = new EvaluatorContext;
foreach (var binging in bindings)
{
var v = binding.getter;
v = binding.f(v, context);
setter(v);
}
}
class Binding
{
public Func<float> getter;
public Func<float> setter;
public Func<float, EvaluatorContext, float> f;
}
}
class EvaluatorContext
{
}
EvaluatorContext добавлен для передачи данных из Evaluator в функцию, например, для передачи информации о времени привязки Binding-а, или о том, что надо всё начать с начала и т.д.
При этом получается такая структура:
1) Драйвер - это либо таймер, либо некоторый объект, который содержит список аниматоров и регулярно дёргает у каждого метод update(currentMs) или step(ms) - смотря как твоему алгоритму удобней.
2) Аниматор - это визитор с одним публичным методом update или step (см. выше. который вычисляет новое значение по заданному алгоритму и дёргает setValue своему объекту. Вычисление значения можно вынести в абстрактный метод calculateValue(currentMs/stepMs) и перекрывать только его.
3) Целевой объект. Должен предоставлять интерфейс getValue/setValue.
В коде это может выглядеть, например, так:
MyObject animated;
animationTimer.addAnimator(new Animator(object) {
protected int calculateValue(int stepMs) {
return (getCurrentValue + stepMs) % 1000;
}
}
можно посмотреть как сделано в каком-нибудь javafx, там исходники открыты.
,
3) Целевой объект. Должен предоставлять интерфейс getValue/setValue.То есть для каждого атрибута, для которого надо иметь возможность менять его, надо добавить в класс сеттер и геттер?
Чет не могу пока проникнуться шаблоном Visitor. Читаю тут - http://www.williamspublishing.com/PDF/5-8459-0393-9/part.pdf Подозрение, что он мне не очень подходит: насколько я понял его рекомендуют применять, если для нескольких классов надо реализовать одну логику, но в моем то случае надо реализовать логику не для класса, а для любого численного атрибута. Хотя я еще до конца не осознал, что происходит, так что версия о том, что не подходит - запросто тупняком может оказаться.
Reflection совсем просто получилось:
Field f = obj.class.getDeclaredField(fieldName);
f.set(obj, currValue);
Field для различных классов можно захешировать в Map или даже все возможные значения при инициализации проги прописать и тогда update будет дергать только f.set(... что по идее не сильно на производительности скажется.
Для каждой функции свой класс писать не хочется, ибо там отличия минимальны и все через case можно разрулить.
P.S. Пошел дальше проникаться шаблоном.
А описание класса Func не требуется разве?В c# Func - это тип из стандартной библиотеки. В Java - это будет java.util.function.Function
Например, задав такую функцию, значение атрибута плавно увеличивается по времени выполнения программы до некоторого значения и становится постояннымЯ бы не стал так делать. Если данные меняются сами по себе, то трудно будет потом понять, как прога работает. ЕМНИП, таймеры в джаве реализованы через потоки, так что еще могут возникнуть проблемы с concurrency. Я бы подумал, к какому месту программы относится вся эта логика, и реализовал бы ее в этом месте.
Программа не очень большая (типа игрушка для сотовых так что можно хоть как делать.
типа игрушка для сотовыхЭто называется tweener, найди готовый или посмотри, как сделаны популярные для Java или других языков.
Вот так, еще чуть-чуть и родился бы велосипед!
Оставить комментарий
0000
Есть несколько (~10) классов, у которых есть float-аттрибуты.Хочется для объектов этого класса и этих атрибутов возможность задавать как будет меняться атрибут по времени, т.е. что-то вроде
Например, задав такую функцию, значение атрибута плавно увеличивается по времени выполнения программы до некоторого значения и становится постоянным.
Пока придумал только заменить атрибуты с float на класс, реализующий логику Функции.
Не нравится то, что будет много объектов класса Eval, которые по сути будут реализовать константу, но их все равно придется каждый раз проверять в update.
В итоге может получится не совсем быстро.
Может кто подскажет как попроще можно сделать?
P.S. Книгу по Java не сильно толстую и толковую посоветуйте еще.