MVCでobserver

ちょっと長いけど、中途半端なサンプルだと一体何のために使うのか分かりづらいので、
最低限どういうときに使えばいいのか分かる程度のサンプルにしてみた。
一応これでもがんばって削りました。

Controller controller;
void mousePressed() { controller.mousePressed(); }
void draw() { controller.dispatcher(); }
void setup() {
  size(400, 300);
  noLoop(); frameRate(30);
  selectScene(scene1); 
}

/////////////////////////////////////////////////
// Scene Manager
/////////////////////////////////////////////////
class Scene { Controller create(){return null;} }
Scene scene1 = new Scene() {
  Controller create() { 
    return new Scene1Controller(); 
  } 
};
Scene scene2 = new Scene() {
  Controller create() { 
    return new Scene2Controller(); 
  } 
};
void selectScene(Scene scene) { 
  controller = scene.create();
}

/////////////////////////////////////////////////
// Controller
/////////////////////////////////////////////////
class Controller implements Observer {
  void mousePressed() {}
  void dispatcher() {}
  void update(Observable o,Object arg){update(arg);}
  void update(Object arg) {}
}
class Scene1Controller extends Controller {
  Scene1Model model;
  void mousePressed() { model.add(); }
  void update(Object arg) {
    int val = (Integer)arg;
    if(val==10) { selectScene(scene2); }
  }
  Scene1Controller() {
    model = new Scene1Model();
    model.addObserver(this);
    new Scene1View(model);
  }
}
class Scene2Controller extends Controller {
  Scene2Model model;
  void mousePressed() { model.add(); }
  void update(Object arg) {
    int val = (Integer)arg;
    if(val==5) { selectScene(scene1); }
  }
  Scene2Controller() {
    model = new Scene2Model();
    model.addObserver(this);
    new Scene2View(model);
  }
}

/////////////////////////////////////////////////
// View
/////////////////////////////////////////////////
class View implements Observer {
  void update(Observable o,Object arg){update(arg);}
  void update(Object arg) {}
}
class Scene1View extends View {
  void update(Object arg) {
    int value = (Integer)arg;
    background(255);
    text(str(value), 100, 100);
    redraw();
  }
  Scene1View(Scene1Model model) {
    model.addObserver(this);
    textFont(createFont("FixedSys", 16));
    fill(0);
    background(255);
    redraw();
  }
}
class Scene2View extends View {
  void update(Object arg) {
    int value = (Integer)arg;
    background(0);
    text(str(value), 100, 100);
    redraw();
  }
  Scene2View(Scene2Model model) {
    model.addObserver(this);
    textFont(createFont("FixedSys", 64));
    fill(255);
    background(0);
    redraw();
  }
}

/////////////////////////////////////////////////
// Model
/////////////////////////////////////////////////
class Model extends Observable { }
class Scene1Model extends Observable { 
  int value = 0;
  void add() { 
    value++; 
    setChanged();
    notifyObservers(value);
  }
}
class Scene2Model extends Observable { 
  int value = 0;
  void add() { 
    value++; 
    setChanged();
    notifyObservers(value);
  }
}

画面をクリックするとシーンが切り替わるサンプル。
Scene1とScene2の処理が一緒過ぎてサンプルにならない気もするけど。
考えるのがめんどくさくなってまぁそこは本質じゃないからどうでもいいやという感じになって考えるのをやめた。


MVCにおいてModelの再利用性を重点においてるからModelはViewとControllerに依存関係を作ってはいけない。
でもそれだとModelの情報によって画面変化などがある場合、
その情報をフックするために無限ループ内に常に Model の情報を監視する処理を入れないといけない。
それは重いので抽象的なもの(依存関係ができないもの)を用意して、
それをModelに呼んでもらおうみたいなそういうコンセプト。


ゲームとかだと無限ループするんでまぁいいやという感じがしないでもないけど、
カードゲームみたいにユーザーの何らかのアクションの後描画がするようなゲームの場合は
毎回ループしてると重いので何らかのデータの変化があったときだけ描画するとこむぷーたーにやさしい。


この場合もほとんどユーザー入力(Controller)からの変化なので
大体の場合ControllerがViewのクラスを呼べばいいんじゃないかという気もするが、
一応知識としては入れておこうみたいな。そういう感じ。