Imagine a class which wraps an external API or read large files or parses huge XML files, fetches data from the Internet or something else. There are thousands of situations like that.

 

In many cases, you can want to not parse/download/load some resources every time, right?. A good option is to use a cache but, to be honest, it’s difficult. In this article I’ll show you a simple and flexible solution.

 

The proxy – this is an answer. The best way to explain is to show an example. You can see a simple class below which fetches some information from external API.

package guru.iamcode.patterns.api;

import guru.iamcode.patterns.ApiRequests;
import guru.iamcode.patterns.Client;
import guru.iamcode.patterns.Order;

import java.util.ArrayList;

public class SomeExternalAPI extends ApiRequests {
    public ArrayList<Order> getLastOrders(int limit)
    {
        return (ArrayList<Order>)get("/v1/orders/latest?limit=" + limit);
    }

    public Client getClientInformation(int clientId)
    {
        return (Client)get("/v1/client/" + clientId);
    }
}

The information doesn’t change very often so it would be handy to cache it somewhere to decrease network consumption. We can achieve it in a few ways. The particulars steps you can find below.

Extend the base class

 

Extending the base class has one key advantage: you can easily replace the base class because both have identical interfaces. Moreover, you don’t have to implement all of the methods – just the one you need to. Great, right?

package guru.iamcode.patterns.api;

import guru.iamcode.patterns.Cache;
import guru.iamcode.patterns.Order;

import java.util.ArrayList;

public class APIOverrideProxy extends SomeExternalAPI {
    Cache cache;

    public APIOverrideProxy(Cache cache) {
        this.cache = cache;
    }

    @Override
    public ArrayList getLastOrders(int limit)
    {
        if (cache.has("last_order_" + limit)) {
            return (ArrayList)cache.get("last_order_" + limit);
        }

        ArrayList Orders = super.getLastOrders(limit);
        cache.put("last_order_" + limit, Orders);

        return Orders;
    }
}

Create an instance of the class in the proxy class

 

The biggest difference between APIDependencyProxy and APIOverrideProxy classes you get instance of the object in a constructor or setter. It’s required to implement the same interface as SomeExternalAPI does but it gives you another advantage. Because you are not fixed to a specific interface. Thanks to that you can add more dependencies and rebuild it completely.

package guru.iamcode.patterns.api;

import guru.iamcode.patterns.Cache;
import guru.iamcode.patterns.Order;

import java.util.ArrayList;

public class APIDependencyProxy {
    private Cache cache;
    private SomeExternalAPI api;

    public APIDependencyProxy(Cache cache, SomeExternalAPI api) {
        this.cache = cache;
        this.api = api;
    }

    public ArrayList getLastOrders(int limit)
    {
        if (cache.has("last_order_" + limit)) {
            return (ArrayList)cache.get("last_order_" + limit);
        }

        ArrayList Orders = api.getLastOrders(limit);
        cache.put("last_order_" + limit, Orders);

        return Orders;
    }
}

Create an instance of the base class if needed

 

Sometimes creating an object can be expensive and not necessarily required. Proxy is a great place to decide which implementation should be used or if the instance is created at all.

package guru.iamcode.patterns.api;

import guru.iamcode.patterns.Order;

import java.util.ArrayList;

public class CreateWhenNeededProxy {
    private SomeExternalAPI heavyAPI;
    private SomeExternalAPI lightAPI;

    private SomeExternalAPI getHeavyAPI()
    {
        if (heavyAPI == null) {
            heavyAPI = new SomeExternalAPI();
        }

        return heavyAPI;
    }

    private SomeExternalAPI getLightAPI()
    {
        if (lightAPI == null) {
            lightAPI = new SomeExternalAPI();
        }

        return lightAPI;
    }

    public ArrayList getLastOrders(int limit)
    {
        return limit > 10 ?
                getHeavyAPI().getLastOrders(limit) :
                getLightAPI().getLastOrders(limit);
    }
}

Summary

 

As you can see, ways of solving the problem can be many. I hope that I’ve given you a lot of inspiration and “A” for your “Q”.What do you thing about the above I prepared? Do you have interesting examples of the Proxy Pattern and want to share them with us? I’m waiting for your comments.

This entry was posted in General, JVM and tagged , by bkielbasa. Bookmark the permalink.