Reputation: 6960
Let's say I have this interface:
public interface MyInterface {
static MyInterface getSingleton() {
return MyDefaultImplementation.getSingleton();
}
//declare some methods
}
and this class:
final class MyDefaultImplementation implements MyInterface {
private static final MyInterface mySingleton = new MyDefaultImplementation();
static final MyInterface getInstance() {
return mySingleton();
}
private MyDefaultImplementation() {
//...
}
//implement interface methods
}
I was wondering if the getSingleton() method of MyInterface should exist or if it is more correct to make MyDefaultImplementation and its getInstance method public. It it's the case, what are the main scenarios in which it makes sense having the getSingleton method in the interface?
Thank you for your time
Upvotes: 0
Views: 1587
Reputation: 298233
An interface can’t be a Singleton. An implementation class may be a Singleton, but that doesn’t prevent other implementation classes of the interface. Therefore, a method named getSingleton()
in an interface, suggesting that the interface was a Singleton, is clearly wrong. While the implementation class is a Singleton, the factory method’s purpose is to hide this implementation from the code using the interface, so it’s contradicting to try to export an information about a property of this hidden implementation class, like its Singleton nature, through the API.
It’s different when it comes to factory methods in interfaces, compare to Stream.empty()
or Java 9’s List.of()
, which do not tell whether the underlying implementation will be a Singleton or not. They provide factories for specialized implementations, which are considered to be fundamental enough to be part of the interface’s API.
This has to be your main consideration too, when thinking about providing factories in an interface. The existence of these implementations is coupled with the interface, even if the actual implementation class is not, so you will always have to bundle the interface with appropriate working implementation classes from then, even if an application might only use the interface to implement it on its own. There might be implementations deserving such treatment. However, if your expectation is to always have this sole Singleton implementation only and no other implementations, there is little reason to use an interface at all.
Upvotes: 1
Reputation: 131376
I was wondering if the getSingleton() method of MyInterface should exist
Your interface becomes both a interface and a factory.
So API and implementation become a same part.
If API and implementations are in the same component (jar for example), in practice, it will not change many things.
But if API and implementations are not in the same component but in two distinct jars : api
and impl
, things are different.
It means that your client has to update both the api
and the impl
component as you add a new implementation in impl
that you return in the getSingleton()
method of the api
.
You didn't change the contract but only the implementation but the client has to update both impl
and api
.
It is undesirable and counter intuitive and it defeats the purpose to separate api and implementation.
Upvotes: 2
Reputation: 70909
The point of an interface is to avoid having the "client" code which uses the interface know about the implementation details of the class. This is critical for future maintenance, as you are designing in the ability to replace the interface's implementation at a future point in time.
If your interface contains a reference of how to "obtain" the underlying implementation, then in order to update your code, you now need to rewrite your interface, and redeploy it. This "change" in the interface based on implementation change, and not "interface" change (adding or removing methods) strongly implies that you are not working within the original intent of the system's design.
Default methods are a relatively new addition to Java. They were not added in the past because without them, it would be impossible to combine implementation into an interface. The addition of them is permitting a lot of scenarios where implementation is defined in the interface, and that is blurring the line between interfaces and abstract classes. In my opinion, that robs the interface of its utility.
Finally, you are using this to create a Singleton
which is a sign that you are using pre-Object-Oriented design practices in your Object-Oriented system. Singletons are ways to introduce unscoped globals. Unscoped globals are what made C/C++ programs very hard to maintain. You would better align your code into an Object that is passed into the methods requiring it. If you need only one instance of that object, an improved code structure can have only one instance created (one call to new) and it will be clear which methods use the object, and which ones don't.
Upvotes: 3
Reputation: 1211
It's more correct to use third object which will provide object implementations.
Like: DI.getBean(MyInterface.class) -> return myDefaultImplementation
.
Or: SingletonServiceFactory.getBean() -> ...
Examples:
Upvotes: 1
Reputation: 4558
In my opinion, it is wrong.
Your interface MyInterface
should not be aware of the implementation MyDefaultImplementation
.
Only your implementation should be aware of your interface.
Upvotes: 0