MVC
Model, View, ControllerでMVC.
Modelはビジネスロジック、Viewは描画、Controllerは操作関連の処理を行う。
参照関係は
- Controller -> Model
- Controller -> View
- View -> Model
Modelは参照先がないのが特徴。
つまりControllerを始点にしてViewを通りModelに終着するのがこのMVCの特徴。
ちなみに参照関係が上述とは違うMVCもあり、それはWebなどでよく使われている。
Model, View, Ctrl
class MyCtrl {
constructor () {
this.model = new MyModel()
this.view = new MyView(this.model)
}
update () {
if (keyboard.isKeyPressed('Enter')) {
this.model.blabla()
}
this.model.update()
this.view.update()
}
draw () {
this.view.draw()
}
}
こーんな感じでControllerを作る。
Viewはこんな感じ。
class MyView {
constructor (model) {
this.model = model
this.canvas = document.createElement('canvas')
document.body.appendChild(this.canvas)
this.ct = this.canvas.getContext('2d')
}
update () {
// nothing todo
}
draw () {
this.ct.fillStyle = 'red'
this.ct.fillRect(0, 0, 100, 100)
}
}
Modelはこう。
class MyModel {
constructor () {
this.count = 0
}
update () {
// nothing todo
}
blabla () {
this.count++
}
}
レイヤー間のイベントの伝達
さて、このパターンはModelで行き止まりだが、ModelからControllerへ何かを伝達したい時はあるものである。
つまり子から親に向かって命令を送る。
親から子に流れている処理に逆らってまるで鯉の滝登りのように子から親に命令という名の下剋上をするのである。
じっさいのMVCでどうやるのかは知らんが、とりあえず返り値は使えそうである。
class MyCtrl {
update () {
let events = this.model.update()
for (let event of events) {
switch (event.kind) {
case EV_EXIT:
this.end = true
break
case EV_NOTICE:
this.view.notice(event.message)
break
}
}
}
}
上みたいにmodelから返り値でイベント列を受け取り、それを処理する。
modelのupdateで色々ビジネスロジックをするわけだが、そのロジックの中でコントローラーに通知したいイベントは上記のように返り値で上層に通知する。うーん、鯉の滝登り!
ModelはCtrlとViewの参照を持っていないので、CtrlとViewを操作することはできない。だが、返り値を使うことで上層レイヤーにイベントを通知、そして上記のthis.view.notice(event.message)
のような感じでイベントを通じてViewを呼び出す。
おわりに
うーん、エレガント! すばらしい!
MVCは不滅だ! MVC! MVC!