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

时间:2012-09-17 15:58:36

标签: java model-view-controller view model controller

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

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

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

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();
    }

}

和控制器:

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();
     }


}

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();
                            }
                         });
    }

}

“命令”界面:

public interface Command {

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

}

和控制器:

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();
     }

 };

}

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

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

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

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

在第二个示例中,控制器控制要做什么,只是对视图说,如果某个按钮(只有视图知道它将是什么按钮)点击该怎么办

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

你能帮助我理解为什么我错了,并向我展示一些例子吗?

1 个答案:

答案 0 :(得分:12)

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

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

在标准MVC中,模型包含并公开数据,控制器操纵模型并接受视图中的事件,视图显示模型并为控制器生成事件。

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

  1. 在视图上生成事件(例如按钮单击)。
  2. 事件信息从视图传递到控制器。
  3. 控制器调用模型上的方法来更改它(setter和其他可能更新某些数据库的操作方法)。
  4. 这些第一步代表V-C链接和M-C链接。存在V-C是因为事件从视图传递到控制器以进行处理而不是直接处理它们的视图。存在M-C链接,因为控制器根据触发的事件更新模型。

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

    1. 交易结束。
    2. 另外,模型会触发自己的事件以表明它已发生变化。
    3. 视图正在侦听模型并接收事件,并更新其模型表示以反映更改。
    4. 第一条路径代表M-V链路的一种解释。 M-V链接是1)视图从模型中获取其数据的信息,以及2)模型告诉视图更新,因为它已被修改。

      第二条路径只有一步:一旦控制器处理完事件,视图只需刷新所有UI元素即可立即更新。对M-V链路的这种解释是模型只是将其信息提供给视图,与上面第一条路径中M-V链路的#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
          }
      }
      

      控制器:

      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();
          }
      }
      

      然后是模型:

      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);
              }
          }
      }
      

      ModelListener非常简单:

      public interface ModelListener {
          void modelUpdated(Model model);
      }
      

      这只是一种解释。如果您想要在不同部分之间进一步分离,您应该查看Presentation, Abstraction, Control (PAC) pattern。它比MVC更加分离,对分布式系统也很有用。对于简单的Web,移动和桌面应用程序来说,它是过度的,但是一些客户端/服务器应用程序和大多数云应用程序都可以从这种方法中受益。

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

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

      无论如何,请遵循架构,文档您的架构(让人们知道您的解释是什么),并且不要偏离它。