我们正在用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的接口?
提前感谢任何澄清,我们对此要求感到有些迷失。
答案 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
接口)