単純なプログラムを書換えよう(Groovy編)−抽象クラス

Commandを抽象クラスにするをまねてGroovyで書いてみよう.

実は,Groovy 1.0-beta6ではコンストラクタをprivateにできない.したがって,CommandDispatcherをSingletonにはできていない.

//Command.groovy
abstract class Command{
  model

  Command(args){
    this.model=args
  }

  void execute(){}
}
//end

//IncCommand.groovy
class IncCommand extends Command{
  IncCommand(args){
    super(args)
  }
  void execute(){
    model++
  }
}
//end

//DecCommand.groovy
class DecCommand extends Command{
  DecCommand(args){
    super(args)
  }
  void execute(){
    model--
  }
}
//end

//CommandDispatcher.groovy
import java.io.File

class CommandDispatcher{
  private static classloader={new GroovyClassLoader().parseClass(new File(it))}
  private static commands=["inc":classloader("IncCommand.groovy"),
                           "dec":classloader("DecCommand.groovy")]
  model

  CommandDispatcher(args){
    //コンストラクタをpriveteにはできない
    model=args.model
  }

  Command command(args){
    Javaで書いて予めコンパイルしておかないとClass.forName(String)が使えない
    return commands[args.type]
      .getConstructor(new Class[]{java.lang.Object})
      .newInstance(new Object[]{this.model})
  }
}
//end

//Controller.groovy
import java.awt.event.ActionEvent
import java.awt.event.ActionListener

class Controller implements ActionListener{
  model
  dispatcher
    
  Controller(args){
    model=args.model
    dispatcher=new CommandDispatcher(model:model) //Singletonにできないのでインスタンスを作る
  }

  void actionPerformed(ActionEvent event){
    dispatcher.command(type:event.getActionCommand()).execute()
  }
}
//end

//Model.groovy
class Model{
  value=0
  observers=[]

  Model next(){
    setValue value+1
    return this
  }
  Model previous(){
    setValue value-1
    return this
  }
  void setValue(value){
    this.value=value
    notifyObservers()
  }

  void add(observer){
    observers.add observer
  }
  void remove(observer){
    observers.remove observer
  }
  void notifyObservers(){
    observers.each{
      it.update(this)
    }
  }
}
//end

//View.groovy
import groovy.swing.SwingBuilder
import java.awt.BorderLayout

class View implements Observer{
  private value

  View(args){
    builder=new SwingBuilder()
    view=builder.frame(defaultCloseOperation:javax.swing.WindowConstants.EXIT_ON_CLOSE,
                       size:[200,100]){
      panel(layout:new BorderLayout()){
        value=label(text:args.init.toString(),constraints:BorderLayout.CENTER)
        panel(constraints:BorderLayout.SOUTH) {
          button(text:'inc').addActionListener args.controller //こう書くとなぜかActionEvent/ActionListenerが使える
          button(text:'dec').addActionListener args.controller
        }
      }
    }
    view.show()
  }

  void update(model){
    value.text=model.value.toString()
  }
}
//end

//Main.groovy
class Main{
  static void main(args){
    model=new Model(value:0)
    controller=new Controller(model:model)
    view=new View(controller:controller,init:0)
    model.add view
  }
}
//end