Установщик вызовов из верхнего уровня иерархии Modelclass - PullRequest
0 голосов
/ 23 февраля 2020

Представьте, что у вас есть иерархия классов моделей, например

    public class TopLevel {
        private MiddleLevel middleLevel = null;

        public TopLevel() {
            middleLevel = new MiddleLevel();
        }

        public MiddleLevel getMiddleLevel() { return middleLevel; }
    }
    public class MiddleLevel {
        private LowLevel lowLevel = null;

        public MiddleLevel () {
            lowLevel = new LowLevel();
        }

        public LowLevel getLowLevel() { return lowLevel; }
    }
    public class LowLevel {
        private Value value = null;

        public LowLevel() {
            value = new Value();
        }

        public Value getValue() { return value; }
    }
    public class Value {
        private String stringValue = "ItsAValue";
        private String doubleValue = 1.0d;
        private String integerValue = 4321;

        public void setStringValue(String value) {
            stringValue = value;
        }
    }

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

Теперь я хочу установить значение в классе Value. Конечно, я могу выполнить что-то вроде:

    TopLevel topLevel = new TopLevel();
    topLevel.getMiddleLevel().getLowLevel().getValue().setStringValue("NewValue");

Есть ли способ упростить или обобщить это, например, чтобы иметь возможность вызывать «путь» через все эти объекты класса, чтобы установить значение глубоко внутри ? Вот какой-то псевдокод, что я имею в виду:

    public class Anotherclass {
        public static void main(String[] args) {
            TopLevel topLevel = new TopLevel();
            setStringValueByPath("topLevel/middleLevel/lowLevel/value/stringValue", "newValue");
            setDoubleValueByPath("topLevel/middleLevel/lowLevel/value/doubleValue", 5.0d);
            setIntegerValueByPath("topLevel/middleLevel/lowLevel/value/integerValue", 1234);
        }

    }

Большое спасибо

Alex

Ответы [ 2 ]

0 голосов
/ 23 февраля 2020

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

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

Переходя к этапу, когда " Нет , Я хочу посмотреть на строковый подход, как указано в вопросе ". Библиотека Apache commons предоставляет что-то под названием JxPath . Не уверен, если вы попытались посмотреть JxPath ref. apache .jx.path

. Он предлагает простой интерпретатор языка выражений под названием XPath. JXPath применяет выражения XPath к графам объектов всех видов

Выбор примера из вашего вопроса:

TopLevel topLevel = new TopLevel();
JXPathContext context = JXPathContext.newContext(topLevel);
context.setValue("middleLevel/lowLevel/value/stringValue", "newStringValue");

0 голосов
/ 23 февраля 2020

Хорошо, если кому-то интересно, я думаю, что нашел решение, которое искал:

Рекурсивный подход, основанный на Java .reflection:

public class ReflectionSetter {
    private static List<Field> getFields(Object object) {
        List<Field> fields = new ArrayList<>();
        fields.addAll(Arrays.asList(object.getClass().getDeclaredFields()));
        return fields;
    }

    private static Field hasField(Object object, String fieldName) {
        for (Field f : getFields(object)) {
            if (f.getName().equalsIgnoreCase(fieldName)) return f;
        }
        return null;
    }

    public static void setValue(Object object, String path, String newValue) throws IllegalArgumentException, IllegalAccessException {
        if (path.contains("/")) {
            int pos = path.indexOf('/');
            String first = path.substring(0, pos);
            String rest = path.substring(pos+1);
            Field f = ReflectionSetter.hasField(object, first);
            if (null == f) throw new IllegalArgumentException("Path not found: " + path);
            f.setAccessible(true);
            Object obj = f.get(object);
            setValue(obj, rest, newValue);
        } else {
            Field f = ReflectionSetter.hasField(object, path);
            if (f == null) throw new IllegalArgumentException("Field not found: " + path);
            // if found -> set value
            f.setAccessible(true);
            f.set(object, newValue);
        }
    }
}

Сейчас Вы можете установить значение через путь. Использование:

    TopLevel topLevel = new TopLevel();
    ReflectionSetter.setValue(topLevel, "middleLevel/lowLevel/value/myValue", "NewValue");
...