Что ж, из вашего поста, даже если он не ясно сформулирован, звучит так, будто вы хотите, чтобы абстрактный класс играл две разные роли.
Роли:
- абстрактная фабричная роль для
(Singleton) сервис, который может иметь
множественно заменяемый
реализации,
- услуга
роль интерфейса,
Кроме того, вы хотите, чтобы служба одноэлементно поддерживала 'singletoness' во всем семействе классов, по какой-то причине вам недостаточно кэшировать экземпляр службы.
Это хорошо.
Кто-то скажет, что он пахнет очень плохо, потому что "нарушает разделение проблем" и "одиночные тесты и юнит-тестирование не сочетаются друг с другом".
Кто-то еще скажет, что это нормально, потому что вы возлагаете на себя ответственность за создание правильных детей в самой семье, а также открываете более свободный интерфейс в целом, поскольку вам не требуется посредничество фабрики, которая не делает ничего, кроме разоблачения статического электричества. способ.
Что неправильно, так это то, что после того, как вы хотите, чтобы дети отвечали за выбор того, какую реализацию должен возвращать родительский метод фабрики.
Это неправильно с точки зрения дизайна, потому что вы делегируете всем дочерним элементам то, что может быть просто перенесено и централизовано в абстрактный суперкласс, а также показывает, что вы смешиваете шаблоны, которые используются в разных контекстах, Абстрактная фабрика (родительский класс решает, какое семейство классов клиенты получат) и Factory Method (детские фабрики выбирают, что получат клиенты).
Фабричный метод не просто не требуется, но и невозможен для фабричных методов, поскольку он сосредоточен на реализации или переопределении «экземпляров» методов. Не существует такой вещи, как переопределение для статических методов или для конструктора.
Итак, возвращаясь к первоначальной хорошей или плохой идее об абстрактном синглтоне, который выбирает, какое поведение выставлять, есть несколько способов решить начальную проблему,
Это может быть следующим, выглядит плохо, но я думаю, что это близко к тому, что вы искали:
public abstract class A{
public static A getInstance(){
if (...)
return B.getInstance();
return C.getInstance();
}
public abstract void doSomething();
public abstract void doSomethingElse();
}
public class B extends A{
private static B instance=new B();
private B(){
}
public static B getInstance(){
return instance;
}
public void doSomething(){
...
}
...
}
//do similarly for class C
Родитель также может использовать отражение.
Более дружественное к тестированию и дружественному расширению решение состоит в том, чтобы просто иметь дочерние элементы, которые не являются одноэлементными, но упакованы во некоторый внутренний пакет, который вы будете задокументировать как «частный» и абстрактный родительский объект, который может предоставлять статическую функцию getInstance (), имитирующую синглтон, и кэшируйте дочерние экземпляры, следя за тем, чтобы клиенты всегда получали один и тот же экземпляр службы.