Лучший способ вызывать разные классы во время выполнения в Java - PullRequest
0 голосов
/ 27 сентября 2018

Давайте представим, что мы должны вызывать один метод из разных классов по определению, поступающий во время выполнения.Например, мы получаем JSON следующим образом:

{"calculator": "MyClass1", "parameter1": 1.0, "parameter2": 2.0, ... }

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

Я могу придумать два способа сделать это:

  1. switch (calculatorString) {case "MyClass1": calculator = new MyClass1 ();...

  2. с использованием Java Reflection

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

Есть ли другие способы сделать это (возможно, лучше)?

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

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

Использование ReflectionAPI

try {
            cls = Class.forName(className);
            instance = cls.newInstance();
            instance = BeanUtils.populateBean(properties, cls);
} catch (Exception e) {
     e.printStackTrace();           
}

BeanUtil Class

public static Object populateBean(Map<String, Object> propertyMap, Class<?> clazz) throws Exception {
    PropertyUtilsBean bean = new PropertyUtilsBean();
    Object obj = null;
    try {
        obj = clazz.newInstance();

        for(Map.Entry<String, Object> entrySet: propertyMap.entrySet()) {
            PropertyDescriptor descriptor = null;
            try {
                descriptor =
                        bean.getPropertyDescriptor(obj, entrySet.getKey());

                if (descriptor == null) {
                    continue;
                }
                Method writeMethod = bean.getWriteMethod(descriptor);
                writeMethod.invoke(obj, convert(descriptor.getPropertyType(), entrySet.getValue(), DATE_PATTERN));

            } catch (IncompatibleConversion e) {
                throw e;
            } catch (Exception e) {
                throw new Exception("Unable to parse");
            }
        }

    }catch(Exception e) {
        throw e;
    }

    return obj;
}

Преобразование класса

private static Object convert(Class<?> clzz, Object value, String datePattern) throws Exception {

    if (clzz.isAssignableFrom(BigInteger.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof BigInteger) {
            return value;
        }

        try {
            return new BigInteger(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(BigDecimal.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof BigDecimal) {
            return parseBigDecimal(value.toString(), DECIMAL_PRECISION);
        }

        try {
            return parseBigDecimal(value.toString(), DECIMAL_PRECISION);
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Integer.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Integer) {
            return value;
        }

        try {
            return new Integer(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Long.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Long) {
            return value;
        }

        try {
            return new Long(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(String.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof String) {
            return value;
        }

        try {
            return value.toString();
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Date.class)) {

        if (value == null) {
            return value;
        }

        if (value instanceof Date) {
            return value;
        }

        if (datePattern == null) {
            throw new Exception("date pattern cannot be null");
        }
        try {

            SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
            return sdf.parse(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Byte.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Byte) {
            return (value);
        } else if (value instanceof Number) {
            return new Byte(((Number) value).byteValue());
        }

        try {
            return (new Byte(value.toString()));
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Float.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Float) {
            return (value);
        }

        try {
            return new Float(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Double.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Double) {
            return (value);
        }

        try {
            return new Double(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    }

    throw new Exception("Incompactible Conversion");
}
0 голосов
/ 27 сентября 2018

Возможно, вы могли бы использовать интерфейс поставщика услуг Java:

См., Например, здесь:

https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html
https://www.baeldung.com/java-spi

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

Вы определяете поставщиков услуг в META-INF

META-INF / services / com.baeldung.rate.spi.ExchangeRateProvider

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

...