package ballworld; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.Timer; import command.*; /** * The "Controller" in a Model-View-Controller architecture * Sets up the appropriate wiring between the model and the view. * Uses event handlers to respond to user input and notifies the model and the view to update accordingly. * Uses a Timer object to update the model and the view at a regular time slice. This will give the effect of animation.   * @dependency ballModel.IStrategy uses * @dependency javax.swing.Timer uses */ public class BallControl2 { private IRandomizer _rand; private int _MaxRadius = 20; private int _MinRadius = 5; private int _MaxSpeed = 20; private Rectangle _MaxVel = new Rectangle(-_MaxSpeed,-_MaxSpeed, _MaxSpeed, _MaxSpeed); private BallGUI2 _frame; private Dispatcher _dispatcher = new Dispatcher(); private SwitcherStrategy _switcher = new SwitcherStrategy(); private ILambda _paintCmd = new ILambda() { public Object apply(Object g) { _dispatcher.notifyAll(g); return null; } }; private ILambda _makeBallCmd = new ILambda(){ public Object apply(Object fac) { if(null!=fac) _dispatcher.addObserver(loadBall(((IStrategyFac)fac).make())); return null; } }; private String fixName(Object classname) { return "ballworld."+classname.toString()+"Strategy"; } private ILambda _makeSwitcherCmd = new ILambda(){ public Object apply(Object nu) { _dispatcher.addObserver(loadBall(_switcher)); return null; } }; private ILambda _switchCmd = new ILambda(){ public Object apply(Object fac) { if(null!=fac) _switcher.setStrategy(((IStrategyFac)fac).make()); return null; } }; private ILambda _clearBallsCmd = new ILambda(){ public Object apply(Object nu) { _dispatcher.deleteObservers(); return null; } }; private interface IStrategyFac { public IUpdateStrategy make(); } private ILambda _addCmd = new ILambda(){ public Object apply(final Object classname) { if(null==classname) return null; return new IStrategyFac() { public IUpdateStrategy make() { return loadStrategy(fixName(classname)); } public String toString() { return classname.toString(); } }; } }; private ILambda _combineCmd = new ILambda(){ public Object apply(Object o) { final Object[] facPair = (Object[]) o; if(null==facPair[0] || null==facPair[1]) return null; return new IStrategyFac() { public IUpdateStrategy make() { return new MultiStrategy(((IStrategyFac)facPair[0]).make(), ((IStrategyFac)facPair[1]).make()); } public String toString() { return facPair[0].toString()+"-"+facPair[1].toString(); } }; } }; private int TimeSlice = 50; private Timer _timer = new Timer (TimeSlice, new ActionListener () { public void actionPerformed (ActionEvent e) { _frame.getContainer().repaint(); } }); /** * Constructor for the BallControl class * Instantiates the BallGUI frame with the required ILambdas for * making a ball, clearing the balls from the screen and for * painting the balls onto the Container * Starts the timer up. */ public BallControl2 (IRandomizer rand) { _rand = rand; _frame = new BallGUI2(_makeBallCmd, _clearBallsCmd, _paintCmd, _makeSwitcherCmd, _switchCmd, _addCmd, _combineCmd); _frame.validate (); _frame.setVisible (true); _timer.start (); } private Ball loadBall(IUpdateStrategy strategy) { return new Ball(_rand.randomLoc(_frame.getContainer().getSize()), _rand.randomInt(_MinRadius, _MaxRadius), _rand.randomVel(_MaxVel), _rand.randomColor(), _frame.getContainer(), strategy); } /** * Uses dynamic class loading to load and instantiate an ABall subclass, given * its class name. */ private IUpdateStrategy loadStrategy(String className) { try { java.lang.reflect.Constructor c = Class.forName(className).getConstructors()[0]; Object []args = new Object[]{ }; return (IUpdateStrategy) c.newInstance(args); } catch(Exception ex) { System.err.println("Class "+className+" not found! Using StraightStrategy instead."); return new StraightStrategy(); } } /** * Entry point to the program. Instantiates a BallControl object and goes away. */ public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch(Exception e) { } new BallControl2(Randomizer.Singleton); } }