// Purpose.  Strategy design pattern

// 1. Define the interface of an interchangeable family of algorithms
// 2. Bury algorithm implementation details in derived classes
// 3. Derived classes could be implemented using the Template Method pattern
// 4. Clients of the algorithm couple themselves strictly to the interface

interface Strategy { public void solve(); }          // 1. Define the interface
                                                     //    of the algorithm
abstract class TemplateMethod1 implements Strategy { // 2. Bury implementation
   public void solve() {                             // 3. Template Method
      start();
      while (nextTry() && ! isSolution())
         ;
      stop();
   }
   protected abstract void    start();
   protected abstract boolean nextTry();
   protected abstract boolean isSolution();
   protected abstract void    stop();
}

class Impl1 extends TemplateMethod1 {
   private int state = 1;
   protected void    start()   { System.out.print( "start  " ); }
   protected void    stop()    { System.out.println( "stop" ); }
   protected boolean nextTry() {
      System.out.print( "nextTry-" + state++ + "  " );
      return true; }
   protected boolean isSolution() {
      System.out.print( "isSolution-" + (state == 3) + "  " );
      return (state == 3);
}  }

abstract class TemplateMethod2 implements Strategy { // 2. Bury implementation
   public void solve() {                             // 3. Template Method
      while (true) {
         preProcess();
         if (search()) break;
         postProcess();
   }  }
   protected abstract void    preProcess();
   protected abstract boolean search();
   protected abstract void    postProcess();
}

class Impl2 extends TemplateMethod2 {
   private int state = 1;
   protected void    preProcess()  { System.out.print( "preProcess  " ); }
   protected void    postProcess() { System.out.print( "postProcess  " ); }
   protected boolean search() {
      System.out.print( "search-" + state++ + "  " );
      return state == 3 ? true : false;
}  }

public class StrategyDemo {    // 4. Clients couple strictly to the interface
   public static void clientCode( Strategy strat ) { strat.solve(); }
   public static void main( String[] args ) {
      Strategy[] algorithms = { new Impl1(), new Impl2() };
      for (int i=0; i < algorithms.length; i++)
         clientCode( algorithms[i] );
}  }

// start  nextTry-1  isSolution-false  nextTry-2  isSolution-true  stop
// preProcess  search-1  postProcess  preProcess  search-2