// Purpose.  Command design pattern - decoupling producer from consumer

import java.util.*;
public class CommandQueue {

interface Command { void execute(); }

static class DomesticEngineer implements Command {
   public void execute() {
      System.out.println( "take out the trash" );
}  }

static class Politician implements Command {
   public void execute() {
      System.out.println( "take money from the rich, take votes from the poor" );
}  }

static class Programmer implements Command {
   public void execute() {
      System.out.println( "sell the bugs, charge extra for the fixes" );
}  }

public static List produceRequests() {
   List queue = new ArrayList();
   queue.add( new DomesticEngineer() );
   queue.add( new Politician() );
   queue.add( new Programmer() );
   return queue;
}

public static void workOffRequests( List queue ) {
   for (Iterator it = queue.iterator(); it.hasNext(); )
      ((Command)it.next()).execute();
}

public static void main( String[] args ) {
   List queue = produceRequests();
   workOffRequests( queue );
}}

// take out the trash
// take money from the rich, take votes from the poor
// sell the bugs, charge extra for the fixes



// Purpose.  Java reflection and the Command design pattern
//
// Motivation.  "Sometimes it is necessary to issue requests to objects without
// knowing anything about the operation being requested or the receiver of the
// request."  The Command design pattern suggests encapsulating ("wrapping") in
// an object all (or some) of the following: an object, a method name, and some
// arguments.  Java does not support "pointers to methods", but its reflection
// capability will do nicely.  The "command" is a black box to the "client".
// All the client does is call "execute()" on the opaque object.

import java.lang.reflect.*;

public class CommandReflect {
   private int state;
   public CommandReflect( int in ) {
      state = in;
   }
   public int addOne( Integer one ) {
      return state + one.intValue();
   }
   public int addTwo( Integer one, Integer two ) {
      return state + one.intValue() + two.intValue();
   }

   static public class Command {
      private Object   receiver;               // the "encapsulated" object
      private Method   action;                 // the "pre-registered" request
      private Object[] args;                   // the "pre-registered" arg list
      public Command( Object obj, String methodName, Object[] arguments ) {
         receiver = obj;
         args = arguments;
         Class cls = obj.getClass();           // get the object's "Class"
         Class[] argTypes = new Class[args.length];
         for (int i=0; i < args.length; i++)   // get the "Class" for each
            argTypes[i] = args[i].getClass();  //    supplied argument
         // get the "Method" data structure with the correct name and signature
         try {      action = cls.getMethod( methodName, argTypes );      }
         catch( NoSuchMethodException e ) { System.out.println( e ); }
      }
      public Object execute() {
         // in C++, you do something like --- return receiver->action( args );
         try {     return action.invoke( receiver, args );     }
         catch( IllegalAccessException e    ) { System.out.println( e ); }
         catch( InvocationTargetException e ) { System.out.println( e ); }
         return null;
   }  }

   public static void main( String[] args ) {
      CommandReflect[] objs = { new CommandReflect(1), new CommandReflect(2) };
      System.out.print( "Normal call results: " );
      System.out.print( objs[0].addOne( new Integer(3) ) + " " );
      System.out.print( objs[1].addTwo( new Integer(4),
                                        new Integer(5) ) + " " );
      Command[] cmds = {
         new Command( objs[0], "addOne", new Integer[] { new Integer(3) } ),
         new Command( objs[1], "addTwo", new Integer[] { new Integer(4),
                                                         new Integer(5) } ) };
      System.out.print( "\nReflection results:  " );
      for (int i=0; i < cmds.length; i++)
          System.out.print( cmds[i].execute() + " " );
      System.out.println();
}  }

// Normal call results: 4 11     // 1 + 3 = 4     // 2 + 4 + 5 = 11
// Reflection results:  4 11