MVC:View是否允许引用模型的可变元素而不修改它们?

时间:2017-05-28 13:31:09

标签: java model-view-controller view model

我们正在用Java开发一个用于学校项目的棋盘游戏,我们正在与我们的导师讨论MVC模式的正确实现(我们需要使用)。

在我们当前的实现中,View被订阅为模型中某些类的Observer,例如可以放置pawn的空间。这个空格有可变字段,如下面的简短示例所示:

public class Space extends Observable {
    private List<Pawn> pawns;
    private Card card;

    // public getters and setters for pawns and card
}

对于我们来说,给这个类提供View直接引用似乎非常直观,这样我们可以每帧查询Space来检索它的状态(我们使用libgdx作为GUI,所以我们每帧都更新窗口)。

现在,即使我们没有在视图中修改模型而只是调用getter,我们的导师说这种方法是不可接受的,因为我们可以从View中修改模型,因为我们是直接引用可变对象,并希望我们添加一个间接层/修改我们的POJO,使View无法修改模型。

YAGNI可以应用于此请求吗?我们设法将模型完全修改为Controller,所以我真的不明白为什么我们应该更改我们的API只是为了限制对Model的访问,即使我们还没有从View中修改它。

此外,由于我们可能会实施他们的请求,完成任务的最佳方法是什么?使视图看到模型类的副本,以便每个修改都没有意义?或者可能创建一个只将不可变对象暴露给View的接口?

提前感谢任何澄清,我们对此要求感到有些迷失。

1 个答案:

答案 0 :(得分:2)

理想情况下,您的View图层将仅使用不可变对象 - 与不可修改的接口不同于其他可变对象 - 使用模型中的必需信息。这些对象将由Controller 跟踪,然后复制到相应的View。 MVC模式可以成功地模拟这种情况。

您需要添加另一个间接层来解决您的设计问题(并且仍然符合MVC)。可能的解决方案如下:

使用您的视图数据模型要求添加新界面:

/** 
* This interface is adopted by an object that mediates
* the application’s data model for a SpaceView object. 
*/
public interface SpaceViewDataSource {
    List<Pawn> getPawns();
    Card getCard()
    ...
}

在您的视图中,存储当前数据源:

public class SpaceView {
    private SpaceViewDataSource dataSource;

    public void setDataSource(SpaceViewDataSource dataSource) {
        this.dataSource = dataSource;
        reloadData();
        ...
    }

    /** The data source has changed. */
    public void reloadData() { ... } 
    ...
}

最后,您的Controller应实现SpaceViewDataSource接口并将自身绑定为SpaceView数据源:

public class SomeController: SpaceViewDataSource, Observer {
    private SpaceView spaceView;
    private Space spaceModel;

    private void configureSpaceView() {
        spaceView.setDataSource(this);
        spaceModel.addObserver(this);
        ...
    }    

    List<Pawn> getPawns() { /* delegate to spaceModel */ }
    Card getCard() { /* delegate to spaceModel */ }

    void update(Observable o, Object arg) {
        if (o == spaceModel) {
            // A fine grained API may be required if
            // this full reload doesn't perform well.
            spaceView.reloadData();
        }
        ...  
    }
    ...
}

在这样做的过程中,我还将您的Controller添加为Space模型观察者

所有这些重构让你回到MVC旅行车上,为你买单:

  • 更多可重复使用的 SpaceView组件(不再与Space模型高度耦合)
  • 明确记录了查看数据模型要求(SpaceViewDataSource接口)
  • 不会绕过Controller层的View-Model通信
  • 控制器跟踪大局,提供更大的灵活性