2012-09-17 31 views
6

正如我在MVC的標準實現中所知,我們將控制器和模型傳遞給視圖MVC - 我需要在視圖中使用控制器嗎?

但是,我有點不同意這個想法。我不希望我的觀點知道控制器和模型(哦不,也許有時候查看需求模型,但我確信他可以在沒有控制器知識的情況下生活)

在我看來,控制器應該管理視圖和模型,而Model不需要了解控制器和視圖;視圖不需要知道控制器(我不排除模型,因爲一些視圖的實現需要知道模型來聽取模型中的變化)。所以我的想法是,視圖不需要知道控制器

下面是一個例子:

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

}; 

}

那麼,爲什麼我認爲,在視圖使用控制器不好

我們是混合控制器並查看實現,創建新的依賴關係。

另外我認爲,視圖應該只包含VIEWS和與他們的操作(並使用控制器和他的一些方法已經看起來像邏輯)。

在第一個示例視圖中告訴控制器該做什麼。你同意嗎?它看起來像視圖控制控制器!

在第二個例子控制器控制做什麼,只是說給視圖做什麼,如果一些按鈕(僅視圖知道它會是什麼按鈕)點擊

我總是使用第二種方案,但看完後一本關於mvc的新書,說我們需要將控制器傳遞給視圖,我有點困惑。

你能幫我理解爲什麼我錯了,給我看一些例子嗎?

+0

我相信,控制器和視圖不直接交互。他們通過模型互動。所以模型知道控制器和視圖,但視圖和控制器不知道彼此。 – gigadot

+2

已經說過了。 MVC有許多變體,實際中的實際作用是不同的。 – gigadot

+0

你是對的..,你怎麼想到在這個例子中,它的實現是更好? – pleerock

回答

11

沒有MVC標準,因爲有很多實現。下面是許多教科書中教授的MVC的一種解釋:

此解釋中控制器的定義是它處理來自視圖的事件,所以視圖必須使用控制器。

在標準MVC中,模型包含並公開數據,控制器操縱模型並接受來自視圖的事件,視圖呈現模型併爲控制器生成事件。

MVC被認爲是一個事務系統,事務由一個事件啓動。這些交易通常如下所示:

  1. 在視圖上生成事件(如按鈕單擊)。
  2. 事件信息從視圖傳遞到控制器。
  3. 控制器調用模型上的方法來改變它(setters和其他可能更新某個數據庫的操作方法)。

這些第一步代表V-C鏈接和M-C鏈接。存在V-C是因爲事件從視圖傳遞到控制器以進行處理,而不是直接處理它們的視圖。存在M-C鏈接是因爲模型由控制器根據被觸發的事件更新。

從這裏,有兩條路徑。第一個:

  1. 交易結束。
  2. 另外,模型會觸發自己的事件以表明它已經改變。
  3. 視圖正在偵聽模型並接收事件,並更新其模型表示以反映更改。

該第一條路徑表示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鏈接。

在任何情況下,遵循的架構,文件你的架構(讓人們知道你的理解是什麼),不從流浪。

+0

感謝您的答覆。我很感謝你的建議,並會了解更多關於PAC模式的信息 – pleerock

+0

誰會在'MyModel'類的'modelListeners' ArrayList中添加'views'?這是否會在'MyController'中完成,在'MyController'類中你會做'模型。 addModelListener(視圖)'? – CapturedTree

+1

當然,我認爲在這個例子中,控制器是合適的地方。所以在控制器構造函數中:'model.addModelListener(view);'或者,你可以讓'View'接口擴展'ModelListener',這樣你就知道它總是一個監聽器。或者讓'View'接口實現一個返回其'ModelListener'的方法。有很多選擇。就像我說的,選擇一個實現,並堅持下去:) – Brian

相關問題