3

I have a coding pattern in java which is some flavor of the strategy pattern. My problem is that the code requires an unchecked cast which I would like to avoid. To explain it briefly, I firstly have a set of classes which share a common interface:

interface IType {}

class TypeA implements IType {}
class TypeB implements IType {}

Then I have a set of strategies which do some specific processing on IType objects.

interface IStrategy<T extends IType> {
    specificProcessing(T o);
}

Lastly, I have a singleton which does some generic processing on ITypes, then fetches the proper IStrategy to do the specific processing. The IStrategy objects are registered in map and I think the method signature ensures that only matching pairs of ITypes and IStrategies go into the map.

class Context {

    private Map<Class<? extends IType>, IStrategy<? extends IType>> map;

    public static Context getInstance() {}

    public <T extends IType> void register(IStrategy<T> s, Class<T> c) {
        map.put(c, s);
    }

    public <T extends IType> void genericProcessing(T o) {
        //do generic stuff with o
        @SuppressWarnings("unchecked") 
        IStrategy<T> s = (IStrategy<T>) map.get(o.getClass());
        s.specificProcessing(o);
    }

}

The "problem" is the unchecked cast warning. I know this happens because the declaration of the map allows non-matching pairs of IType and IStrategy. I also know that the code is type safe because of register(). But is there any other design which avoids the unchecked cast?

I would appreciate any input, thanks.

bewi
  • 321
  • 3
  • 9
  • I was trying to think of a way that you could have `TypeA`, `TypeB`, etc., store the `IStrategy` as static members for each type, and then have a polymorphic `IType` method return the static member, that you could call via `o.getStrategyForType()`. Problem is, I think that to be polymorphic it would have to return `IStrategy` with no type parameter, and then casting to `IStrategy` would still be an unchecked cast. – ajb Jun 14 '14 at 18:31
  • Yes exactly, this would move the unchecked cast to another class. I think at the core the problem is that there is no way (at least afaik) to declare a map which enforces the use of compatible `Class`, `Strategey` pairs. – bewi Jun 14 '14 at 19:59
  • 1
    Helpful/related question: http://stackoverflow.com/questions/6139325/heterogeneous-container-to-store-genericly-typed-objects-in-java?lq=1 – Rob Marrowstone Jun 14 '14 at 21:50
  • @Hoons, thanks. This post is kind of a duplicate of mine and it seems it's impossible to do what i want. I just thought that maybe more experienced people may have an idea how to change the design to solve it. – bewi Jun 14 '14 at 22:45

1 Answers1

1

There is no way to avoid it when using this map. I would suggest moving the map access into a separate method, so the code reads more cleanly.

@SuppressWarnings("unchecked")
private <T extends IType> IStrategy<T> getStrategy(T o) {
    return (IStrategy<T>) map.get(o.getClass());
}

BTW, you can do it in scala.

Edit:

You can do it in Octarine, see blog on post Extractors. But maybe this is just a fancy way or moving the logic to it's own method, but bringing in a lot of complexity.

David Roussel
  • 5,788
  • 1
  • 30
  • 35
  • Thanks, the post that Hoons linked in the comments above comes to the same conclusion. I'll leave the question open until Monday and accept the answer then. – bewi Jun 14 '14 at 22:49