0

I have an engine that creates strategies for text file processing. These files are in various formats and the engine selects an appropriate strategy by passing the file through a chain of strategies until one of them asserts it can parse it.

This is not quite the classic strategy pattern. It's somewhat similar to the Service Locator Pattern and Chain Of Responsibility patterns, and could incorporate aspects from any of them.

Stripped down it looks a bit like this, although it's currently created with injection:

        public class EngineImpl {

            private Set<Strat> strategies = new HashSet<Strat>();

            public EngineImpl(){
                registerStrategy(new ConcreteStrat1());
                registerStrategy(new ConcreteStrat2());
            }

            public void registerStrategy(Strat strat){
                strategies.add(strat);
            }

            public Strat getStrategy(SomeClass input){
                for (Strat s: strategies)
                    if (s.canParse(input)
                         return s;
                return null;
            }

        }

As it stands, the problem is that the EngineImpl must know all the available strategies at compile time for this to work and I'd like to be able to deploy new strategies without changing the EngineImpl code. I've looked elsewhere for options to do this in Java and come up with blanks. I considered making Strat classes register themselves with the Engine, but they would never get loaded by the classloader and so would never get the chance to register.

What alternative methods could I use to register strategies? Although I'm currently using DI I'm open to other reflection and/or annotation based solutions.

tom
  • 2,704
  • 16
  • 28

1 Answers1

0

Ok, so for now I think I'm going to do the following, which although far from ideal does at least tie it in with the rest of my dependency management.

add an init method to the Strat interface (implementaions are expected to register themselves);

public void init(Engine e);

create and inject each Strat in my GuiceModule which creates the singleton and calls the injected method.

bind(ConcreteStrat1.class).asEagerSingleton();

There are problems with this approach that I hope can be solved. The Strat objects must annotate their init method with @Inject or it will never be called. Eclipse helpfully copies this in when it inserts the method stubs, but otherwise it's unenforceable as far as I can tell. I'm no sure how this will work with "dropped in" strategies but I guess in the absence of anything better I'll cross that bridge later.

eta: I'm now writing javascript strategies that can be loaded from the database, which makes it easily pluggable with a JavascriptStrategyManager

tom
  • 2,704
  • 16
  • 28