DevOps Zone is brought to you in partnership with:

Marcin is an experienced architect who specializes in creating high quality software. Being under the impression of the Agile methodologies and the Software Craftsmanship movement, he believes in the value of good, testable and maintainable code. He aims to forge good software that makes the client delighted and the team proud of how the code itself looks. In his teaching, as a conference speaker, college lecturer, IT coach and trainer, he shows how to guide software development effectively using tests (with TDD, pair programming, Clean Code, design patterns, etc.) and maintaining a quality-oriented development environment (with CI, Sonar, automatic deployment, etc.). He is also a FOSS projects author and contributor, a Linux enthusiast. The author of Mockito refcard. Marcin has posted 1 posts at DZone. You can read more from them at their website. View Full User Profile

Null Object Pattern Implementation in Groovy

07.23.2014
| 6878 views |
  • submit to reddit

Simple real life problem. The proper service implementation is taken from a map based on a given service key. For an unknown/unsupported key a meaningful exception should be thrown. How could it be implemented without an if statement?

Business context. PriceProvider allows to get price for the requested product. A concrete implementation call proper provider via Web Service (REST or SOAP). There is a delegate/dispatcher which depending on a given provider name/id selects the proper implementation.

Implementation note. Mapping selected provider to the corresponding provider adapter implementation can be implemented in many ways. An external properties file, a records in a database or even have a separate web interface. However in many cases those connections are rather permanent and do not need to be changed at runtime. Then a simple map is a very compact and efficient solution. No, 6 “if..else..if..” statements are not the option :-).

There is a map with pairs: provider id -> provider service. It could be initialized (in Java) for example with:

Map<PriceProviderKey, PriceProvider> map = new EnumMap<>(PriceProviderKey);
javaMap.put(PriceProviderKey.PROVIDER1, provider1Service);
javaMap.put(PriceProviderKey.PROVIDER2, provider2Service);
(...)

On checkPrice() call proper provider service should be selected to perform a request:

// PriceProviderDelegate
 
public PriceResult checkPrice(PriceRequest request) {
    PriceProvider provider = map.get(request.getProvider());
    if (provider == null) { //Not very elegant
        throw new UnsupportedOperationException(
            String.format("Operator %s is not supported", request.getOperator()));
    }
    return provider.checkPrice(request);
}
I don’t like ifs like that. The first idea could be an old good Null Object Pattern:

class DefaultPriceProvider implements PriceProvider {
    @Override
    public PriceResult checkPrice(PriceRequest request) {
        //We don't have access to operator name which causes this exception
        throw new UnsupportedOperationException("Operator ??? is not supported");
    }
}
The problem is that we need to implement all methods from the interface and what is worst we don’t know which provider id caused the situation to put it in the exception.

Then I recalled this code is in Groovy and my thoughts went to closure coercion. At the end it turned out that Groovy has a very nice mechanism for it. We can use Map.withDefault(Closure) method which allows to define logic to calculate returned value for unknown keys.

Technical insight. Under the hood Groovy creates a wrapper which for unknown keys calls the closure and put its execution result into a map (for given key). Therefor even for complicated logic its cost is paid only once – on the next query the value is got directly from a map.

Usually a constant/calculated value is returned:

def map = [a:1, b:2].withDefault{ -1 }

but in our case inside the closure we can just throw an exception:

def map = [(PriceProviderKey.PROVIDER1): provider1Service,
           (PriceProviderKey.PROVIDER2): provider2Service]
    .withDefault{ providerKey ->
            throw new UnsupportedOperationException("Provider ${providerKey} is not supported")
    }

Then checkPrice() code can be reduced to just positive flow:

public PriceResult checkPrice(PriceRequest request) {
    def priceProvider = map.get(request.provider);
    priceProvider.checkPrice(request);
}

I like places when Groovy can simplify my code so much!

Published at DZone with permission of its author, Marcin Zajączkowski. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)