4

I'm trying to do something clever. I am creating a weather application in which we can replace the weather API with another weather API without affecting the code base. So I started with a Maven project with multiple modules.

I have a Base module that contains the Interface class and the Base class. The Interface class contains the calls to the APIs (all calls are similar, if not exact) and the Base class contains the properties to the APIs (again, all properties are similar, if not exact).

I have a module for each of the two weather APIs we are testing with plans to create more modules for new weather APIs as we grow the application.

Finally, I have created a Core module (includes main) to implement the specific module class for the weather API I want to test.

Now, I know the simplest way to do this would be to use a switch statement and enumeration. But I want to know if there is a more clever way to do this. Maybe using a Pattern? Any suggestions?

Here is a picture of the structure I have just described:

enter image description here

Here is the UML representation:

enter image description here

This is a learning process for me. I want to discover how a real Java Guru would implement the appropriate module and class based on a specified configuration.

Thank you for your suggestions.

saljuama
  • 2,906
  • 1
  • 20
  • 42
Patricia
  • 5,019
  • 14
  • 72
  • 152

3 Answers3

3

I'm trying to do something clever. I am creating a weather application in which we can replace the weather API with another weather API without affecting the code base.

Without reading further down, this first statement makes me think about a plugin architecture design, but in the process of software design, decisions must not be rushed, the more you delay, the more information you have and a better informed decision can be made, for now is just an idea to keep in mind.

I have a Base module that contains the Interface class and the Base class. The Interface class contains the calls to the APIs (all calls are similar, if not exact) and the Base class contains the properties to the APIs (again, all properties are similar, if not exact).

When different modules share behaviour/state, it is a good idea to refactor them and produce base abstract classes and interfaces, so you are on the right track, but, if there are differences, those shouldn't be refactored into the base module. The reason behind that is simple, maintainability. If you start adding if clauses or switches to deal with these differences, you just introduced coupling between modules, and you'll be always having to make changes in the base module, whenever you add/modify other modules, and this is not desirable at all.

This is reflected by the Open/Closed principle form the SOLID principles, which states that a class should be open for extension but closed for modifications.

So after you've refactored the common behaviour into the base modules, then each new API should extend the base module, as you did.

Finally, I have created a Core module (includes main) to implement the specific module class for the weather API I want to test.

Now, I know the simplest way to do this would be to use a switch statement and enumeration. But I want to know if there is a more clever way to do this. Maybe using a Pattern? Any suggestions?

Indeed, making use of a switch, makes it work, but its not a clean design at all, for the same reason as before, when adding, modifying or removing modules, would require to modify this module aswell, and also this code can potentially break.

One possible solution, would be to delegate this responsability on a new component and make use of a creational design pattern like the Abstract Factory, which will provide a interface to instantiate components without specifying its classes.

As for the architecture, so far, the plugin architecture still makes sense, but what if the different modules extend the base contract adding more features? One option is to use the Facade pattern to adapt the module calls and provide an output that implements an interface that clients expect.

But then again, with the provided details, this is the solution I'd suggest, but the scenario should be studied carefully and in greater detail, in order to be able to assure that these are the right tools for the job, and commit to them.

saljuama
  • 2,906
  • 1
  • 20
  • 42
  • Thank you so much! This is exactly what I was hoping for. Now to start looking into your suggestions. Cheers. – Patricia Dec 23 '15 at 20:49
  • Hi, Salvador! I have discovered that even though I am using Java's SPI, as explained René's answer, I still need to use Abstraction in order to call the appropriate methods of the plug-in. I hope this comment will be helpful to others. Thanks again for the information. :-) – Patricia Jan 12 '16 at 16:14
  • 1
    i find using abstractions / interfaces a good way to avoid coupling also, so i generally use it quite often. Glad you doing ok :) – saljuama Jan 12 '16 at 23:59
3

In addition to Salvador Juan Martinez's answer...

To implement a plugin architecture Java's Jar File Specification provides support for service provider interfaces (SPI) and how they are looked up.

As of Java 1.6. you can use the ServiceLoader to lookup service providers. For Java 1.5. and less you must do it on your own or use a library. E.g. commons-discovery.

The usage is quiet simple. In your case put a META-INF/services/com.a2i.weatherbase.IWeather file in each plugin module.

In the Weather Forecast IO module the file should contain only one line

 com.a2i.weatherforecastio.ForecastIO

The line must be the full quallified name of an IWeather implementation class.

Do the same for the other module and you can load the implementations via ServiceLoader.

ServiceLoader<IWeather> weatherServicesLoader = ServiceLoader.load(IWeather.class);
Iterator<IWeather> weatherServices = weatherServicesLoader.iterator();

Now it depends on your runtime classpath how many services will be found. Try to add and remove module jar archives from the classpath and run your application.

EDIT I wrote a blog about a pluggable architecture with standard java. See http://www.link-intersystems.com/blog/2016/01/02/a-plug-in-architecture-implemented-with-java/

Source code is also available at https://github.com/link-intersystems/blog/tree/master/java-plugin-architecture

Community
  • 1
  • 1
René Link
  • 48,224
  • 13
  • 108
  • 140
  • 1
    since I suggested plugin architecture, but also pointed out that without more details, couldn't really asure it was the best option, didn't want to go further, but anyways, really nice addition :) – saljuama Dec 25 '15 at 19:11
  • Hey, René, I've decided to use your approach but I'm doing something wrong. I'm trying to run a JUnit test in Netbeans and my iterator is 0, so I must not be loading my service classes. My dependencies point to my other projects in the IDE. Do I need to also put the jars somewhere? – Patricia Jan 04 '16 at 23:50
  • Great blog, BTW. I downloaded your code and used it as my example. I created a unit test and tried to run your project and the iterator is 0 there as well. I think I found my answer here: http://stackoverflow.com/a/29205130/1735836 – Patricia Jan 05 '16 at 00:49
  • Hey, René, I ran in to difficulties using ServiceLoader for a multi-module project. So, I put out another question here: http://stackoverflow.com/q/34619176/1735836 – Patricia Jan 05 '16 at 19:43
  • @MissLucy Ok, I will take a look soon. – René Link Jan 05 '16 at 20:44
0

One solution is you have to define the common interface with all the identified common operations. The extensions/plugins need to implement that interface and have to provide the implementation to common operations.

You can use an abstract factory design pattern to hook up the exact implementation at runtime based on the input parameters.

Interfaces and abstract classes are always good in such scenarios, Thanks.