синглтон и наследование в Java - PullRequest
8 голосов
/ 25 марта 2011

У меня есть базовый класс, который фиксирует некоторые функции, общие для двух классов. Другими словами, я могу создать один базовый класс и сделать эти два класса подклассами этого базового класса. Однако для каждого из этих подклассов количество экземпляров, которое может быть создано, равно 1 (т.е. каждый подкласс должен быть одиночным). Я погуглил и обнаружил, что по этому поводу идут разумные дебаты. Хотя есть несколько доступных решений, я не уверен, подойдут ли они в моем случае.

Может кто-нибудь сказать мне, как я должен разработать это?

Ответы [ 6 ]

2 голосов
/ 25 марта 2011

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

Возможно, вы не захотите повышенной сложности, но такие фреймворки, как Spring были созданы для решения подобных проблем (среди прочих).

Кажется, что Pico Container жив и здоров, и это может быть самый простой, хотя и твердый раствор.Посмотрите на инверсию тем управления и позвольте фреймворку внедрять синглтоны там, где они вам нужны.

Короче, не пытайтесь заставить синглтонов управлять доступом к себе.Передайте это другому:

Нет ничего плохого в том, чтобы иметь одноэлементные классы со сложным наследованием.На самом деле иерархии классов с закрытыми конструкторами (без экземпляров) очень полезны во многих ситуациях.Вам просто нужно решить, как вы хотите управлять двумя важными аспектами синглетонов: созданием и доступом.

2 голосов
/ 25 марта 2011

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

0 голосов
/ 09 февраля 2018

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

public abstract class AbstractCache<T> {

    protected final Map<String, T> cache;

    protected AbstractCache() {
        this.cache = getDefaultExpiringMap(TimeUnit.HOURS.toMillis(4));
    }

    public Map<String, T> getCache() {
        return cache;
    }

    public T getAll(String id) {
        return cache.get(id);
    }
}

Затем я расширил этот класс и создал одноэлементный экземпляр:

public final class FooCache extends AbstractCache<Set<Integer>> {

    public static final FooCache INSTANCE = new FooCache();

    private FooCache() {
        super();
    }

    public void add(String fooId, Integer value) {
        cache.computeIfAbsent(fooId, k -> new HashSet<>()).add(value);
    }
}

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

public static void main(String[] args) {
    FooCache.INSTANCE.add("a", 1);
    System.out.println(FooCache.INSTANCE.getAll("a"));
}
0 голосов
/ 03 августа 2014

Наследование - не единственный способ повторно использовать обычную функциональность.Сдерживание может быть предпочтительнее в общем случае.Рассмотрим следующее решение, в котором классы A и B являются синглетонами, а общая функциональность - в классе AB, но вместо расширения AB, A и B используют экземпляр AB, который сам является одиночным.

class AB { //common functionality of A and B
   //singleton pattern here
   //common data and functionality here
}
class A {
   private AB ab = AB.getInstance();
   //singleton pattern here
   //unique functionality and data of A

   //to use any of the functionality in AB delegate to member ab
}

класс B аналогичен A.

. В этом решении есть один экземпляр всех данных и функций как A, так и B (и AB)

Обратите внимание, что если клиенты Aи B необходимо получить доступ к общим открытым методам в AB, тогда AB, A и B должны реализовать интерфейс этих открытых методов, а реализация A и B должна делегировать вызов ab.


Решение, предложенное Эрнестом ниже, в некоторых ситуациях может быть сокращением, но в целом это неправильное решение.

Чтобы объяснить, почему решение Эрнеста может быть неправильным, давайте опишем, чтоРешение по-другому.Предположим, у меня есть одноэлементный класс A, и я обнаружил, что мне нужно написать еще один одноэлементный класс B, но мне нужны некоторые функциональные возможности A в B. Поэтому я выделяю общие данные и функциональные возможности A в абстрактный класс AB и создаюи A и B расширяют AB.В общем, причина его неправильности в том, что это решение берет подмножество данных и функциональных возможностей, которые должны существовать только один раз, и помещает их в подкласс (AB), эффективно и потенциально дублируя их в каждом подклассе.класс, который будет создан.Теперь, после получения экземпляра A и экземпляра B, у вас есть два экземпляра данных подмножества и функциональности в AB.

Если, например, общая функциональность, размещенная в базовом классе, записывает некоторые исходные данные в файл с именем «myData», то оба ваших синглета будут выполнять этот код, даже если он должен был быть выполнен только один раз,и когда последний выполнит его, он уничтожит файл, созданный первым.

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

0 голосов
/ 25 марта 2011

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

Базовый класс:

  public abstract class BaseClass {

        public void someMethod() {
            System.out.println("base class hello: " + this);
        }

        public abstract void someOtherMethod(String value);
    }

Один из подклассов:

public class SubClassOne extends BaseClass {

    private static SubClassOne instance;

    private SubClassOne() {}

    public static SubClassOne getInstance() {
        if (instance == null) {
            instance = new SubClassOne();
        }
        return instance;
    }

    public void someOtherMethod(String value) {
        someMethod();
        System.out.println("sub class hello: " + value + " " + this);
    }

    public static void main(String[] args) {
        SubClassOne one = SubClassOne.getInstance();
        SubClassOne two = SubClassOne.getInstance();
        SubClassOne three = SubClassOne.getInstance();
        SubClassOne four = SubClassOne.getInstance();
        one.someOtherMethod("one");
        two.someOtherMethod("two");
        three.someOtherMethod("three");
        four.someOtherMethod("four");
    }
}
0 голосов
/ 25 марта 2011

Я не специалист по Java, поэтому я не знаю, является ли это технически допустимым кодом Java (возможно, другой автор может прокомментировать):

Сделать базовые классы наследуемыми от универсального класса Singleton.

Пример:

class Singleton<T> {

    protected Singleton(); //constructor

    private static T _instance;

}

class DerivedOne extends Singleton<DerivedOne>{

    protected DerivedOne(){} //constructor
}

class DerivedTwo extends Singleton<DerivedTwo>{

    protected DerivedTwo(){} //constructor
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...