You are trying to get an abstract class play two very different roles:
- the abstract factory role for a
(singleton) service that can have
multiple substitutable
implementations,
- the service
interface role,
and on top of that you also want the service to be singleton and enforce 'singletoness' on the entire family of classes, for some reason you aren't considering caching the service instances.
Somebody (I would) will say it smells very bad, for multiple reasons
it violates separation of concerns,
singletons make unit testing impossible",
etc.
Somebody else will say it's ok-ish, it doesn't need a lot of different infrastructure and has kind of fluent-ish interface that you see in some very common third party (legacy) Java API.
The bad part is demanding the children to select what implementation should the parent factory method return.
That responsibility should be pushed up and centralised into the abstract superclass. Otherwise you are mixing together patterns that are used in very different contexts, Abstract Factory (parent decide what family of classes clients are going to get) and Factory Method (children factories select what the clients will get).
Factory Method is also not practically possible because you can't override static methods, nor constructors.
There are some (ugly) ways to achieve your objective though:
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
The parent could also use reflection, cache instances, etc.
A more test and extension friendly solution is simply standard separation of concerns. The children aren't going to be singleton anymore per se, but you package them into some internal package that you will document as "private" and a public abstract parent in an external package will handle caching or pooling of children instances, enforcing whatever instantiation policy is required on these classes.