using Optional and Suppliers to implement strategy pattern

246 views Asked by At

I implemented the code below as a nice generic solution to get something by trying one strategy after another until I find something or return empty if unsuccessful.

import java.util.Optional;
import java.util.function.Supplier;

public class StrategyEvaluator {

    /**
     * Evaluate supplier stategies that produce Optionals until one returns something.
     * @param suppliers
     * @return the optional provided by the first successful supplier or Optional.empty()
     */
    @SafeVarargs
    public static <T> Optional<T> evaluate(Supplier<Optional<T>>...suppliers) {
        for(Supplier<Optional<T>>s: suppliers) {
            Optional<T> maybe = s.get();
            if(maybe.isPresent()) {
                return maybe;
            }
        }
        return Optional.empty();
    }
}

This here is an example of how I use it:

public Optional<Contact> getContactForOwner(boolean cached, String contactId, String ownerId, boolean followLinks) {

    return StrategyEvaluator.evaluate(
            () -> getFromDao(cached, contactId, ownerId, followLinks),
            () -> getUserProfileContact(cached, contactId),
            () -> searchContactByIdAndHandles(contactId, ownerId)
    );
}

So, this works quite nicely and seems to do what it needs to do and it is a lot better than the nested if else's it replaced. However, I'm wondering if I'm not reinventing wheels here and whether there are better ways to do the same. Also I'm wondering whether there are any downsides to this approach in terms of overhead or generics weirdness? Varargs and generics don't really play that well with each other for example, hence the @SafeVarargs.

I'm trying to avoid more heavy handed solutions like for example having a Strategy builder that has a list of suppliers and an evaluate method that I need to assign to an instance which I then reuse (i.e. the traditional Strategy pattern). I'm aiming for a tradeoff between having few lines of code when using it and not too much overhead. This looks kind of neat at least and it does the job.

0

There are 0 answers