MVC - 我是否需要在视图中使用Controller?

ple*_*ock 7 java model-view-controller controller model view

正如我所知,在MVC的标准实现中,我们将Controller和Model传递给View

但我有点不同意这个想法.我不希望我的视图知道控制器和模型(哦不.有时可能需要查看模型,但我确信他可以在没有控制器知识的情况下生活)

在我看来,Controller应该管理View和Model,而Model不需要了解控制器和视图; 视图不需要知道控制器(我不排除模型,因为一些视图实现需要知道模型来监听模型中的变化).所以我的想法是视图不需要了解控制器.

1.下面是一个例子:

public class MyView implements ButtonClickListener {

    private Controller myController;
    private Button myButton;

    // I commented out the model because we dont need it now 
    // we are talking about using controller in the view

    public MyView(Controller c/*, Model m*/) {
        myController  = c;
        myButton      = new Button(); // lets say that it is "register" button
        myButton.setOnButtonClickListener(this);
    }

    public void setRegisterButtonText(String text) {
        myButton.setText(text);
    }

    @Override
    public void onClick() {
        myController.tellToModelToDoSomething();
    }

}
Run Code Online (Sandbox Code Playgroud)

和控制器:

public MyController implements Controller {

     private Model model;
     private View view;

     public MyController(Model model) {

          this.model = model;
          this.view  = new MyView(this);

     }

     public void tellToModelToDoSomething() {
          model.doSomeActions();
     }


}
Run Code Online (Sandbox Code Playgroud)

2.现在如何在不通过控制器的情况下看到此实现:

我的看法:

public class MyView {

    private Button myButton;

    public MyView() {
        myButton = new Button();
    }

    public void setRegisterButtonText(String text) {
        myButton.setText(text);
    }

    public void setOnRegisterButtonClick(final Command command) {
        myButton.setOnButtonClickListener(new ButtonClickListener() {
                            @Override
                            public void onClick() {
                                command.execute();
                            }
                         });
    }

}
Run Code Online (Sandbox Code Playgroud)

"命令"界面:

public interface Command {

     void execute(/*also can handle extra params*/);

}
Run Code Online (Sandbox Code Playgroud)

和控制器:

public MyController implements Controller {

 private Model model;
 private View view;

 public MyController(Model model) {

      this.model = model;
      this.view  = new MyView();

      view.setOnRegisterButtonClick(command);

 }

 public void tellToModelToDoSomething() {
      model.doSomeActions();
 }

 private Command command = new Command() {

     public void execute() {
          tellToModelToDoSomething();
     }

 };
Run Code Online (Sandbox Code Playgroud)

}

那么为什么我认为在视图中使用控制器不是很好:

我们正在混合控制器和视图实现,从而产生新的依赖关系.

另外我认为View应该只包含VIEWS和它们的操作(并且使用控制器和他的一些方法看起来像逻辑).

在第一个示例视图中告诉控制器要做什么.你同意吗?它看起来像控制控制器!

在第二个示例中,控制器控制要执行的操作,并且只是对视图说,如果某个按钮(只有视图知道它将是什么按钮)单击该怎么办

我总是使用第二种方案,但在阅读了一本关于mvc的新书后,说我们需要将控制器传递给视图,我有点困惑.

你能帮我理解为什么我错了,给我看一些例子吗?

Bri*_*ian 12

没有MVC标准,因为有许多实现.以下是许多教科书中对MVC的一种解释:

此解释中控制器的定义是它处理视图中的事件,因此视图必须使用控制器.

在标准MVC中,模型包含并公开数据,控制器操纵模型并从视图接受事件,视图呈现模型并为控制器生成事件.

MVC被认为是事务系统,其中事务由事件启动.交易通常如下所示:

  1. 在视图上生成事件(例如按钮单击).
  2. 事件信息从视图传递到控制器.
  3. 控制器调用模型上的方法来改变它(setter和其他可能更新某些数据库的操作方法).

这些第一步代表VC链接和MC链接.VC存在是因为事件从视图传递到控制器以进行处理而不是直接处理它们的视图.MC链接存在,因为控制器根据触发的事件更新模型.

从这里开始,有两条路径.第一个:

  1. 交易结束.
  2. 另外,模型会触发自己的事件以指示它已发生变化.
  3. 视图正在侦听模型并接收事件,并更新其模型表示以反映更改.

第一条路径代表MV链接的一种解释.MV链接是1)视图从模型获取其数据的信息,以及2)模型告诉视图更新,因为它已被修改.

第二条路径只有一步:一旦控制器处理完事件,视图就会立即刷新所有UI元素.对MV链接的这种解释是模型简单地将其信息提供给视图,与上面第一路径中的MV链接中的点#1相同.

以下是我为您描述的MVC架构修改的一些代码:

public class MyView implements View, ModelListener {

    private Button myButton;
    private Controller controller;

    public MyView(Controller controller, Model model) {
        myButton = new Button();
        myButton.setOnButtonClickListener(new ButtonClickListener() {
            @Override
            public void onClick() {
                controller.onRegisterButtonClick();
            }
        });
        this.controller = controller;
        model.addModelListener(this);
    }

    public void setRegisterButtonText(String text) {
        myButton.setText(text);
    }

    public void modelUpdated(Model model) {
        // Update view from model
    }
}
Run Code Online (Sandbox Code Playgroud)

和控制器:

public MyController implements Controller {

    private Model model;
    private View view;

    public MyController(Model model) {
        this.model = model;
        this.view  = new MyView(this, model);
    }

    private void manipulateModel() {
        model.doSomeActions();
    }

    public void onRegisterButtonClick() {
        maniuplateModel();
    }
}
Run Code Online (Sandbox Code Playgroud)

那么模型:

public class MyModel implements Model {
    private List<ModelListener> modelListeners = new ArrayList<ModelListener>();

    public void addModelListener(ModelListener ml) {
        if (!modelListeners.contains(ml)) {
            modelListeners.add(ml);
        }
    }

    public void removeModelListener(ModelListener ml) {
        modelListeners.remove(ml);
    }

    public void doSomeActions() {
        // Do something
        fireUpdate();
    }

    private void fireUpdate() {
        // Iterates backwards with indices in case listeners want to remove themselves
        for (int i = modelListeners.size() - 1; i >= 0; i-- {
            modelListener.modelUpdated(this);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

ModelListener 非常简单:

public interface ModelListener {
    void modelUpdated(Model model);
}
Run Code Online (Sandbox Code Playgroud)

这只是一种解释.如果您希望在不同部分之间进一步解耦,则应查看演示,抽象,控制(PAC)模式.它比MVC更加分离,对分布式系统也很有用.对于简单的Web,移动和桌面应用程序来说,它太过分了,但是一些客户端/服务器应用程序和大多数云应用程序都可以从这种方法中受益.

在PAC中,您有三个部分,表示,抽象和控制,但抽象和表示(模型和视图)不会相互交互.相反,信息仅传入和传出控制模块.此外,您可以拥有多个PAC子模块,这些子模块只能通过其控件相互交互,从而为分布式系统提供良好的模式.基本上,控制模块是任何数据传输的主要枢纽.

从本质上讲,您对MVC的解释可能与我或他们的不同.重要的是,您选择一种架构模式并遵循它以保持您的代码在未来可维护.你是对的,有办法进一步解耦MVC.实际上,您的示例有点像PAC,但它不是删除VC链接,而是删除MV链接.

无论如何,遵循一个架构,记录您的架构(让人们知道您的解释是什么),并且不要偏离它.