Android Design patterns Featured Java Software Engineering

How to minimize your dependency on third party libraries?

Introduction

I guess that you are in similar situation like me, that most projects that you are working on are dealing with third party libraries.  There is no need to reinvent the wheel, since external libraries are usually well tested and documented solutions made by other developers to make your life easier. You should use them ,since there is almost nothing wrong with using third part libraries, because they can make our development much faster and save us a lot of time.

What is the problem?

The main problem is that you become tightly coupled to that external library and that is something that we should try to avoid as much as possible.  You will end up with multiple calls to external library from your concrete code and as result you can not easily replace your 3rd party library, because you will need to find every call to external library and change it’s implementation.

Solution

Solution to this problem is using Facade design pattern. Facade hides the complexities of a system and provides an interface to a client from where a client can access a system. It is structural design pattern which main goal is to hide complexity of a system from a client. If you are not familiar with Facade design pattern you can read article from the link below:

By making facade around a third party library you are adding an additional layer of abstraction on top of it. Some advantages are:

  • Your code is easier to change
  • Easier testing
  • Multiple concrete implementations of external libraries
  • Low coupling

In general, your goal is to have system that is easier to change, so you can change your a third party library with another one.

Example

Nobody likes theory, so I will show you concrete real world example with an Android application that need to load images from Internet. If you are working with Android you probably know that there is a lot of image loading libraries, since working with images on Android is very hard and time consuming.

One of the most popular solution was Universal Image Loader library, but the main developer announced that he does not have time for development. So that could be a problem for us, since concrete code of this library is across all of our code base and we should found every ImageView component and change code that loads image inside it.

Let’s see how to write code with Facade design pattern that is easy to change, so we can easily remove Universal Image Loader with Picasso image loading library.

Step 1

First we need to set up our project by creating project and add INTERNET and WRITE_EXTERNAL_STORAGE permission inside Android Manifest file.

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Also we need to add Gradle dependencies inside module build.gradle file:

compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'

Step 2

We need to define an interface, which will use to wrap image loading libraries.

public interface ImageLibrary {
    void load(String url, ImageView imageView);
}

 Step 3

Since in this example we initially used Universal Image Loading library, let’s first write implementation for that library. We will create UniversalImageLibrary class that will implement ImageLibrary interface.

public class UniversalImageLibrary implements ImageLibrary {

    private final ImageLoader imageLoader;

    public UniversalImageLibrary(Context context){

        // Create global configuration and initialize ImageLoader with this config
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context).build();

        imageLoader = ImageLoader.getInstance();
        imageLoader.init(config);
    }

    @Override
    public void load(String url, final ImageView imageView) {
        imageLoader.loadImage(url, new ImageLoadingListener() {
            @Override
            public void onLoadingStarted(String imageUri, View view) {
            }

            @Override
            public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
            }

            @Override
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                imageView.setImageBitmap(loadedImage);
            }

            @Override
            public void onLoadingCancelled(String imageUri, View view) {
            }
        });
    }
}

Step 4

Now let’s create class for Picasso image loading library.

public class PicassoImageLibrary implements ImageLibrary {

    private Context context;

    public PicassoImageLibrary(Context context){
        this.context = context;
    }

    @Override
    public void load(String url, ImageView imageView) {
            Picasso.with(context).load(url).into(imageView);
    }
}

Step 5

Let’s create class that will serve as facade and hide concrete implementations. First version is using Universal Image Loader library as concrete implementation. If you are already familiar with Facade design pattern, then you can easily remove Facade from class name, since you know class intent and purpose.

public class ImageLoaderFacade {

    private  Context context;

    public ImageLoaderFacade(Context context){
        this.context = context;
    }

    public void load(String url, ImageView imageView){
        UniversalImageLibrary universalImageLibrary = new UniversalImageLibrary(context);
        universalImageLibrary.load(url, imageView);
    }
}

Universal Image Loader library is not active, so let’s change our implementation to Picasso. We need just change load method to call class that has Picasso concrete implementation.

public class ImageLoaderFacade {

    private  Context context;

    public ImageLoaderFacade(Context context){
        this.context = context;
    }

    public void load(String url, ImageView imageView){
        PicassoImageLibrary picasso = new PicassoImageLibrary(context);
        picasso.load(url, imageView);
    }
}

Step 6

It is time to write some code inside our Activity class. We need to create facade instance and pass image URL and concrete image view.

public class MainActivity extends AppCompatActivity {

    private String IMAGE_URL = "http://photos.wikimapia.org/p/00/03/04/64/07_big.jpg";

    private ImageView imageView;

    private ImageLoaderFacade imageLoaderFacade;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = (ImageView) findViewById(R.id.imageView);

        imageLoaderFacade = new ImageLoaderFacade(this);
        imageLoaderFacade.load(IMAGE_URL, imageView);
    }
}

Conclusion

As you can see, we have easily changed from Universal Image Loader to Picasso, since we wrote concrete implementation of Picasso library and inside our Facade class just changed call to Picasso class. Without this approach, we would end hunting all image loading calls and changing concrete implementation of Universal Image Loader library to Picasso.

You should use external libraries, since they will speed up your development and you will have more time to solve your business problems. This does not mean that you must make facade around every external library, but general idea is that you do not want to be dependent to them.  Use Facade design pattern when you are expecting to change external library, library is not trusted or you just want to use just small subset of library without exposing the whole library to the client.

You Might Also Like

No Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.