Implementing service priorities

In the last example, we got two instances of SortUtil, and we did something ridiculous with them--we sorted the list twice, once per implementation! You wouldn't typically do that. What you'll most likely need to do in applications when you receive more than one service implementation is something a bit trickier. You'll need to choose one!

Unfortunately there is no way you can give service implementations distinct priorities. So, there's no way you can say something like BubbleSortUtilImpl is your favorite sort implementation, and that's the implementation to be used if it's available, irrespective of whatever other implementations are found. As per design, it's not the responsibility of the service implementations to specify priority. It's the job of the consumer to decide what to do with the multiple implementations it receives from ServiceLoader, since the best service implementation for the job is usually dependent on the consuming application itself. What is the best service implementation for one consumer might not be ideal for another.

Now, how does the consumer choose one provider among all available ones? All it sees is a bunch of instances of the same interface! So, what we do is enhance the interface to contain methods that the consumer can use to query provider instances. The consumer calls these methods to find out more about the provider classes and thus make an informed decision about which provider instances it would like to go with.

Take the case of the SortUtil implementations. Let's assume we want to use the sorting algorithm depending on the size of the list. For instance, let's say we wish to choose bubble sort only if the list is very small, but use the Collections API sorting for larger lists.

What we could do is add a method to the SortUtil interface called getIdealInputLength(). Each implementation then provides an integer length that it can deal with ideally.

Bubble sort is far from the best sorting algorithm you can use. It's an algorithm many programming courses use to teach sorting, but in reality it's horribly inefficient. For the sake of our simple example, let's say we use bubble sort on lists that are four elements or smaller, and use Collections sort for the rest. I'll admit this is a contrived example, but it'll let us implement a basic strategy for choosing providers. In reality, you'd almost always want to use the Collections API for sorting lists.

Here's SortUtil with the new method declaration:

    public interface SortUtil { 
      public <T extends Comparable> List<T> sortList(List<T> list); 
      public int getIdealMaxInputLength(); 
    } 

Here's the BubbleSortUtilImpl implementation of this method that returns 4 as the ideal maximum size of the input list:

    public class BubbleSortUtilImpl implements SortUtil { 
      ... 
      public int getIdealMaxInputLength() { 
        return 4; 
      } 

The JavaSortUtilImpl is OK with any list size, so for the ideal maximum, we'll just return the maximum integer value:

    public class JavaSortUtilImpl implements SortUtil { 
      ... 
      public int getIdealMaxInputLength() { 
        return Integer.MAX_VALUE; 
      } 

Now that each provider has a method that can be used to choose one implementation over the other, the consumer can use this to identify which of the implementations it would like to use.

Here's the section in Main.java (in both the pack.addressbook and packt.addressbook.ui modules) that loops through the providers to pick one:

    Iterable<SortUtil> sortUtils =
ServiceLoader.load(SortUtil.class); for (SortUtil sortUtil : sortUtils) { logger.info("Found an instance of SortUtil with ideal
max input: " + sortUtil.getIdealMaxInputLength()); if (contacts.size() < sortUtil.getIdealMaxInputLength()) { sortUtil.sortList(contacts); break; } }

Given the size of the contacts list we'd like to sort, we'll check each provider to see if the list size is greater than the maximum size the provider would ideally like to handle. We then pick the first provider that passes this check, use that instance to sort the list, and break off the loop.

Run the code and observe the output. If the BubbleSortUtilImpl is the first instance in the iterator, the logic skips it and moves to the JavaSortUtilImpl and uses it to sort:

$ java --module-path out -m packt.addressbook/packt.addressbook.Main 
Apr 09, 2017 8:01:20 PM packt.addressbook.Main main 
INFO: Address book viewer application: Started 
Apr 09, 2017 8:01:20 PM packt.addressbook.Main main 
INFO: Found an instance of SortUtil with ideal max input: 4 
Apr 09, 2017 8:01:20 PM packt.addressbook.Main main 
INFO: Found an instance of SortUtil with ideal max input: 2147483647 
[Charles Babbage, Tim Berners-Lee, Edsger Dijkstra, Ada Lovelace, Alan Turing] 
Apr 09, 2017 8:01:20 PM packt.addressbook.Main main 
INFO: Address book viewer application: Completed 

This is a simple example of how provider implementations give clues about the implementation to any consumers. Different consumers could then choose different implementations, depending on their unique needs and business problems.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.97.53