Как я могу получить синглтон, полученный из абстрактного базового типа в Java?

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

Если я поместил общую функциональность в базовый класс, который наследуется от общего предка, я получаю класс, который не имеет смысла создавать экземпляр, поэтому я сделал его абстрактным. Кроме того, поскольку все классы используются как синглтоны, все они должны иметь метод init() и getInstance(), которые являются статическими. Все конструкторы, конечно, не являются общедоступными.

Теперь, поскольку static является незаконным модификатором для абстрактных методов, следующее не работает, хотя это было бы именно то, что я хочу:

class Base extends LibraryClass {
    protected Base() {
        // ... constructor
    }

    // ... common methods

    // ILLEGAL!
    public static abstract void init();
    public static abstract <T extends Base>T getInstance();
}

class A extends Base {
    private static A _INSTANCE;

    private A() {
        super();
    }

    public static void init() {
        _INSTANCE = new A();
    }

    public static A getInstance() {
        return _INSTANCE;
    }
}

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

Ответ 1

Это невозможно в Java. Существование методов static не может быть выполнено; ни с помощью abstract, ни с помощью interface.

Мое решение заключалось в том, чтобы использовать IoC в некотором смысле: я создал класс factory для одиночных чисел. Это спасло бы синглтоны на карте. Ключ будет классом. Таким образом, я мог бы сказать:

A singleton = Factory.create (A.class);

Основное преимущество этой конструкции: я могу создать метод Factory.replace(), где тестовые примеры могут переопределять синглтоны.

Ответ 2

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

public class UsefulThing {

}

public final class SingletonOfUsefulThing {
    private static UsefulThing instance;

    private SingletonOfUsefulThing() {}

    public UsefulThing getInstance() {
        if (instance == null) {
            instance = new UsefulThing(); 
        }

        return instance;
    }
}

Это позволяет вам отдать некоторые из основных преимуществ одноэлементного класса для класса без каких-либо последствий, которые реализуют синтаксическую семантику в классе, что напрямую заставляет вас иметь дело, и позволяет некоторым помещениям для изменения определенного типа класса, re exposing как singleton (с помощью factory для создания экземпляра, например, вместо new.

Ответ 3

Вы не можете выразить, что дочерние классы имеют определенные статические методы.

На самом деле не должно быть необходимости делать это, поскольку статические методы будут вызваны непосредственно на дочерние классы (A.init() и A.getInstance() в вашем примере) и никогда не будут ссылаться на базовый класс (т.е. статические методы не поддерживают полиморфизм).

Ответ 4

Почему бы вам не пройти весь путь и сделать ваш factory (в базовом классе) передать параметр, указывающий, какой подкласс вам нужно вернуть. Есть много преимуществ для этого, и несколько недостатков.

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