MVCアーキテクチャの実装

javaで実装してみた。"1."などのコメントは、エントリMVCアーキテクチャ - @katzchang.contextsの図に対応しています。

珍しくクラス図なんて書いてみたけど、こんなんでいーんでしょうか?


class user.User

ユーザはMVCシステムを定義し、ビューを取り出し、ビューのボタンを押したり(1.)、ビューの内容を見たり(6.)できる。

package user;

import mvc.MVC;
import mvc.View;

public class User {
    public static void main(String[] args) {
        MVC mvc = new MVC();
        
        View view = mvc.getView();
        System.out.println(view.display()); //prints "初期状態"
        
        //1.
        view.button.push();
        //6.
        System.out.println(view.display()); //prints "ボタンが押された"
    }
    
}

class mvc.MVC

MVCアーキテクチャ全体、つまりModel, View, Controllerの関係を表現する、公開されたクラス。

図によると、MVCに向かう矢印、つまりMVCへの外からのアクセスはViewだけになっているので、Viewのみ可視としている。

package mvc;

public class MVC {
    private Model model;
    private View view;
    private Controller controller;
    
    public MVC() {
        this.model = new Model();
        this.controller = new Controller(model);
        this.view = new View(model, controller);
    }
    
    public View getView(){
        return view;
    }
}

class mvc.View

Viewはユーザからの矢印があるので、外部から可視な、公開されたクラスとした。

ViewはModelとControllerに向かう矢印を持っている。ということは、ModelとControllerに対する操作を行うということなので、両者をメンバとして持っている。
ユーザが操作するためのボタンを公開してて、ユーザはそのボタンを押すとControllerに通知する(2.)。

また、ユーザはビューの表示を見ることができる(5.)。

package mvc;

public class View {
    private final Model model;
    private final Controller controller;
    
    public Button button = new Button();
    
    public View(Model model, Controller controller) {
        this.model = model;
        this.controller = controller;
    }
    
    public class Button {
        public void push() {
            //2.
            controller.push(this);
        }
    }
    
    public String display() {
        //5.
        return model.getStatus();
    }
}

class mvc.Controller

Controllerは外部からの矢印がないので、mvc外から不可視なクラスとした。
ボタンが押されると、Modelに対してボタンが押された旨を通知する(3.)。

package mvc;

import mvc.View.Button;

class Controller {
    private final Model model;
    
    Controller(Model model) {
        this.model = model;
    }
    
    void push(Button button) {
        //3.
        model.setStatus("ボタンが押された");
    }
}

class mvc.Model

Modelも外部からの矢印がないので、mvc外から不可視なクラスとした。
statusの問い合わせに返答するほか、status変更通知を受け取ると、自身のstatusを変更する(4.)。

package mvc;

class Model {
    private String status = "初期状態";
    
    String getStatus() {
        return status;
    }
    
    void setStatus(String status) {
        //4.
        this.status = status;
    }
}

雑感

図示による概念の整理は重要。
思えば、今までパッケージ可視/不可視とかって適当に設定してたけど、結構使えるかも知れない。いや、使えるかどうかはわからないけど、興味深い。

多くのアプリケーションではデータの格納に永続的な記憶の仕組み(データベースなど)が使われている。MVCの概念では、データの(UI以外の)入出力は取り扱わないので、データアクセスも本来MVCの概念の範疇を超えるものではあるが、敢えていえばmodelの中に隠蔽されると考えられる。
wikipedia:Model_View_Controller

今回は、「矢印の元となるオブジェクトは先となるオブジェクトを操作するため、メンバとして保持する」というパターンで実装した。
もしもDBを使うように拡張する場合、図によるとModelからDBへの矢印のみがあるので、実装するとしたら「ModelオブジェクトはDBオブジェクトをメンバとして持つ」となると思うが、これは「modelの中に隠蔽される」と同義になる。