Why is the provider interface necessary? Could we just as easily register the Service (s) ourselves? save the implementation map of the Service, and then return the instance when searching?
As others have argued, the goal of the Provider is to have an AbstractFactory that can instantiate the Service
. You do not always want to refer to all implementations of the Service, because they can be short-lived and / or cannot be reused after their implementation.
But what is the purpose of the provider and how can you use the "Provider Registration API" if you do not have a provider
One of the most serious reasons to have a provider interface is that you do not need to have an implementation at compile time. Users of your API can add their own implementations later.
Let me use JDBC as an example, like Ajay used in another answer, but let's look at it a bit further:
There are many different types of databases and database providers that have slightly different ways to manage and implement databases (and possibly query them). Java creators cannot create implementations of all these different possible ways for many reasons:
- When Java was first written, many of these companies or database systems did not yet exist.
- Not all of these database providers are open source, so Java creators cannot know how to communicate with them, even if they want to.
- Users can write their own personal database.
So how do you solve this? Using Service Provider
.
- The Driver interface is a
Provider
. It provides methods for interacting with specific vendor databases. One of the methods in Driver
is the factory method to make an instance of Connection
(which is Service
) for the database, taking into account the URL and other properties (such as username and password, etc.).
Each database provider writes its own implementation of Driver
to communicate with its own database system. They are not included in the JDK; You must go to the company’s websites or some other code repository and upload them as a separate bank.
To use these drivers, you must add jar to your classpath, and then use the JDK DriverManager
class to register the driver.
The DriverManager class has a registerDriver(Driver)
method that is used to register a driver instance with the registration service so that it can be used. By convention, most Driver
implementations are registered during class loading, so all you have to do in your code is write
Class.forname("foo.bar.Driver");
Register the driver for the provider "foo.bar" (if you have a jar with this class in your class path.)
After registering the database drivers, you can get an instance of the service implementation that is connected to your database.
For example, if you had a mysql database on your local computer named "test" and you had a user account with username "monty" and password "greatsqldb", you can create a service implementation as follows:
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" + "user=monty&password=greatsqldb");
The DriverManager class sees the line you went into and finds a registered driver that can understand what this means. (This is done using the Chain of Responsibility
template, going through all the registered drivers and calling their Driver.acceptsUrl(Stirng)
method until the URL is accepted)
Note that there is no mysql specific code in the JDK. All you had to do was register the driver of any provider, and then pass the properly formatted string to the service provider. If later we decide to use another database provider (for example, oracle or sybase), we will simply replace the banks and change our connection string. The code in DriverManager does not change.
Why have we not only once established a connection and saved it? Why do we need a service?
We may want to connect / disconnect after each operation. Or we might want to keep in touch longer. Having a service allows us to create new connections whenever we want, and does not prevent us from storing a link to it for reuse later.
This is a very powerful concept and is used by frameworks to allow many possible permutations and extensions without cluttering up the core codebase.
EDIT
Working with multiple providers and providers that provide multiple Services
:
Nothing prevents you from having multiple providers. You can simultaneously connect to multiple databases created using other database provider software. You can also connect to multiple databases produced by the same provider at the same time.
Several services. Some providers may even provide different implementations of the Service
, depending on the connection URL. For example, H2 can create filesystem-based or memory-based databases. The way to specify the H2 you want to use is a different URL format. I did not look at the H2 code, but I believe that file-based and memory-based are different service implementations.
Why does DriverManager not only manage Connections, and can Oracle implement OracleConnectionWrapper? No providers!
It will also require you to know that you have an Oracle connection. This is a very tight connection, and I would have to change a lot of code if I changed providers.
Service Registration
just takes a string. Remember that it uses chain of Responsiblity
to find the first registered provider that knows how to handle the URL. the application can be a neutral provider and get the connection URL and driver class name from the properties file. This way, I do not need to recompile my code if I change the providers. However, if I rigidly linked the links to "OracleConnectionWrapper", and then I changed the providers, I would have to rewrite part of my code and then recompile.
There is nothing to stop anyone from supporting multiple database provider URL formats if they want to. Therefore, I can make a GenericDriver that could handle mysql and oracle if I wanted to.