Вызовите объект Kotlin с передачей класса из Java в качестве статического метода

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

Предположим, что у нас есть интерфейс и класс Facade (в Java), например:

interface FacadeInterface<T> {
    void method(String from, String via);
}

class Facade<T> implements FacadeInterface<T> {
    private Class<T> mClazz;

    public Facade(Class<T> clazz) {
        mClazz = clazz;
    }

    @Override
    public void method(String from, String via) {
        System.out.println("Method called from " + from + " via " + via);
    }
}

В моих приложениях мне нужно иметь несколько синглтонов, которые содержат экземпляр фасада. Реальный фасад имеет дополнительные параметры настройки/конфигурации, но здесь они неактуальны.

Прежде чем я начал использовать kotlin, у меня был бы класс, который содержит статический экземпляр фасада (на самом деле это не синглтон, но в моем случае он служил аналогичной цели), который проксировал вызовы на фасад, например:

public class Singleton {
    private static final FacadeInterface<String> sFacade = new Facade<>(String.class);

    private Singleton() {
    }

    public static void method(String from, String via) {
        sFacade.method(from, via);
    }
}

Теперь с Kotlin у нас есть делегаты класса, которые позволяют мне написать что-то вроде этого:

object SingletonKt : FacadeInterface<String> by Facade(String::class.java)

Это здорово - не больше шаблонов, и я могу назвать SingletonKt из классов Kotlin так же, как я назвал java Singleton:

Singleton.method("Kotlin", "Singleton")
SingletonKt.method("Kotlin", "SingletonKt")

Но возникает небольшая проблема, когда я использую SingletonKt из Java. Затем я должен указать INSTANCE:

Singleton.method("Java", "Singleton");
SingletonKt.INSTANCE.method("Java", "SingletonKt");

Я знаю аннотацию @JvmStatic, но единственное место, где я могу помещать его в файл SingletonKt не вызывая ошибок компиляции, находится прямо перед FacadeInterface и похоже, что это не трюк.

Есть ли способ настроить делегат этого класса, чтобы я мог его вызывать из Java, как если бы это был статический метод, без введения шаблона создания прокси-методов для SingletonKt (что бы победить цель делегата класса)?

Ответ 1

Это, к сожалению, не возможно!

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

Вторая проблема, с которой вы сталкиваетесь в отношении @JvmStatic на самом деле более радикальна по отношению к вашему делу, чем первая, а также применима к вам при реализации делегирования вручную:

Элементы переопределения не могут быть "@JvmStatic" в объекте

Поэтому вместо того, чтобы разоблачить method() помощью INSTANCE, вы можете делегировать его staticMethod() для объекта. Это по-прежнему отличается от ваших намерений, но приближается к нему.

object SingletonKt : FacadeInterface<String> by Facade(String::class.java)
    @JvmStatic fun staticMethod(from: String, via: String) = method(from, to)
}

Ответ 2

Я не знаю, можно ли делегировать методы как статические методы внутри объекта в Котлине.

Однако, поскольку вы заинтересованы в создании синглонов, которые проксируют класс, вы можете использовать константы уровня пакета в Kotlin:

val SingletonKt : FacadeInterface<String> = Facade(String::class.java)

Теперь вы можете вызвать SingletonKt.method же, как и на Java. Обратите внимание, что вам нужно использовать статический импорт в Java, чтобы использовать константу SingletonKt.

Это также позволяет использовать такие функции, как lazy только создавать синглтон (или, в данном случае, экземпляр), когда вам это нужно.