3

我正在開發一個應用程序,我使用的是MVC模式。目前我的計劃是爲每個窗口提供一個MVC模式。例如,我的登錄窗口有自己的mvc系統。另一個他們選擇的窗口有自己的mvc系統。然後主視圖有自己的mvc系統...多窗口設計的mvc

這似乎有點愚蠢。我想知道這是否正常,讓每個窗口都有自己的mvc?如果沒有,我怎麼能更好地安排呢?

我遇到的問題是,我如何獲得窗口mvc中的日誌以正確調用選擇窗口,然後在他們做出選擇之後,選擇窗口如何調用mainview窗口?

感謝您的幫助!如果您需要更多信息,請告訴我。

+0

我將使用MVC複雜的任務開始,並沒有那麼多簡單的「一次性」類型的任務。所有這一切(在我心中)的關鍵是連接。你想創建一些容易插入你的程序或任何其他需要此功能的類似程序,所以你需要限制代碼的[耦合](http://en.wikipedia.org/wiki/Coupling_( computer_science))儘可能多。 –

+3

MVC是一種很好的模式,但嚴格執行MVC是一種反模式IMO。有意義時使用MVC,但不要爲了MVC而做MVC。 –

+1

你可以看看這個[示例](http://stackoverflow.com/questions/3066590/gui-problem-after-rewriting-to-mvc/3072979#3072979)來幫助縮小你的問題。我會讓模型狀態的「已認證」部分,並讓視圖作出相應的反應。用模態對話框響應切換登錄/註銷按鈕。 – trashgod

回答

3

如何正確地從登錄窗口調用該選擇窗口?

使用observer pattern。如果任何視圖更改模型的狀態,則會通知所有註冊的偵聽器,並且每個都可以自行更新以反映更改。這個example提到了三種實現觀察者模式的常用方法。

+0

我明白這一點。但是,我從哪裏啓動窗口。我有控制器啓動窗口,查看器還是模型?哪個最好?現在我只是讓控制器啓動窗口。 – prolink007

+3

讓控制器啓動窗口。該模型是數據和唯一的數據。視圖是將模型呈現給用戶的手段。模型和視圖都不是你開窗的合理地點。 – DwB

+1

我不明白你的架構足夠肯定,但絕對不是模型。只要確保任何新發布的窗口在首次可見之前就作爲相關模型的觀察者註冊。 – trashgod

1

其實我相信我要做的是使用中介模式來控制這些視圖之間的交互。這種方式的耦合是非常有限的,它得到了我想做的確切工作。讓我知道你的想法。

+0

是一箇中介是一個很好的解決方案,實際上一個通知中心主要用作全局主線程中介。 –

2

儘管它很簡單,但MVC模式還有許多時間不瞭解。首先,您需要了解所有這些分離的組件應該包含哪些內容以及它們如何一起討論。

  • 該視圖:任何UI元素。一個好的可重用視圖元素應該在任何地方重用。因此,視圖不知道它的上下文,也不知道他將與之交互的控制器。視圖知道的是它自己的狀態和一個(或很多)通用監聽器,一旦發生某些動作,它將調用它。視圖元素知道它的狀態,廣播改變,但不應該自己改變它的狀態。例如:一個按鈕將播放一個「點擊」動作,並且您將通過一個控制器通過如下方法設置按鈕名稱:aButton.setLabel("click me!");

  • 模型:模型能夠處理數據集的狀態,它通常實現一些函數爲了保存並從文件中加載它的狀態。模型是一個實際上不應該改變其狀態的盒子,除非有人(管理員)要求它。再次,一個好的模型不知道視圖甚至控制器。這只是它的方式。一個非常簡單的模型就是一個String。您可以從文件加載字符串,將其保存到文件中,將其更改爲大寫字母,子字符串等。一個字符串有一個狀態,不知道它的上下文,只是等待某個人使用它。如果模型知道你被欺騙的控制器,那麼除非你實現了同一個控制器(即使使用接口這是一個糟糕的做法),該模型將不可重用。

  • 控制器:控制器實際上是您的程序,這是制定決策部分的部分。在哪兒 ?以及...你的main function已經是控制器。再次,所有的決定都被製成一個控制器。當有人點擊一個按鈕時,控制器中的一個方法被調用(而不是一個視圖),當你想更新一個標籤時,你可以從控制器上執行。所有的線程也應該被處理成控制器。你的模型正在加載一個大文件?創建一個線程進入控制器,要求模型加載圖像,然後通知主線程進行一次(出話題,搜索事件循環)

多個窗口,我們在這裏!

查看/控制器他們如何互相交流? 該視圖的責任僅僅是爲控制器提供事件(文本字段已更改,單擊按鈕等)並能夠以我們想要的方式顯示。例如window.setTitle(「myWindow」);我們可能會試圖將東西放入應該放入控制器的視圖中,反之亦然。

例如,如果您正在構建警報面板,您將有2個按鈕(ok,cancel)和一個文本標籤。點擊「取消」的「確定」後,視圖是否知道該怎麼做?當然不是......但一旦點擊,面板將不得不自行消失。相反,如果您確實創建了輸入密碼的面板,則視圖將無法保存驗證過程。這將是控制者的工作是否同意所提供的密碼。

好吧,我想你明白所有的MVC,現在是時候談談,讓所有這些組件連接在一起說話的正確方法:

應該如何的看法是通知控制器?其實這取決於你使用的語言。首先想到以下幾點:

  • 避免查看控制器。
  • 視圖不應該從控制器獲取信息,也不應該調用它的方法。它如何告訴控制器發生了什麼事?通過觀察者(或聽衆)

小括號:視圖可以調用另一個視圖的方法,如果它只是保持視覺上正確的問題。例如,調整窗口大小將確保此窗口的所有組件(子視圖)仍能正確顯示,但控制器可能不會通知窗口已更改大小。

MVC之間的通信是關鍵!那麼,它是如何工作的?

  • 誰將創建並顯示視圖?控制器!

  • 誰應該註冊才能查看事件?控制器太...創建後

  • 如何?該視圖的工作是在事件發生時進行廣播。通常通過java中的ActionListener,objective-c中的觀察者,lambda函數C++,javascript中的函數回調。並且控制器列出來,在java中實現正確的「回調」功能actionPerformed,選擇器,或者如果您爲視圖提供了函數回調,則甚至可以直接使用回調函數。

  • 因此,當從控制器創建的視圖觸發事件時,控制器會收到通知,並且必須處理此事件。如果控制器想要將某些東西改變爲視圖,那很容易導致控制器始終擁有並知道該視圖。

  • 給每個窗口一個控制器:聽起來不錯,你不必在創建登錄控制器對象實例時只有一個控制器(無論是一個模型還是視圖...),可以創建並顯示登錄窗口爲好。

  • 每個服務的模型的一個實例。單身人士設計模式就是這樣,您可能只需要一個「身份驗證模型」,因爲您在同一個應用程序中登錄或註銷。因此,不是爲依賴於登錄狀態的每個窗口創建多個登錄模型實例,而是實際上只想要一個。您可以通過登錄模型對象的靜態實例來完成此操作。這被稱爲單身人士。

現在如何確保我們改變成模型將被複制到所有控制器?簡單的情況是一個控制器和一個模型。控制器正在更改模型,並等待模型被更改爲使用更改(例如將其顯示到視圖中)。如果模型通過多個控制器共享會發生什麼?例如,該模型是一個登錄服務,您有2個狀態:登錄和註銷。 2控制器正在使用這個模型,每個控制器都有它自己的視圖(窗口),一個只顯示一個密碼字段,另一個是一個窗口,只有當用戶登錄時才顯示圖像。對這種情況不是一種解決辦法,而是幾種。一種是使用聆聽/觀察模式。幾個控制器可以監聽模型的變化。一旦其中一個正在改變它,所有的控制器將被通知更改,因此將更新視圖。另一種方法是保留一個通知中心(這是另一種模式),並讓控制器或模型廣播所發生的事件,所有對此事件感興趣的控制器將隨後通知變化並處理事件。最後的解決方案對於模型隨時可能更改的情況(當然通過隱藏在某處的控制器)尤其有用。通知中心正在使用事件循環並嘗試大部分時間通知主事件循環(這應該是您的UI控制器的線程)

因此,對於我們的示例,如果登錄過程處於脫機狀態,我將使用簡單監聽器。 2個控制器正在監聽模型更改。輸入密碼後一個控制器將調用方法的模型login.loginWithPassword(String some password)如果密碼正常,模型將廣播一個事件「loginStateChanged」。所有的監聽者(包括我們的2個控制器)都會得到這個事件,並告訴視圖隨我們想要的更新(例如顯示只有在記錄時才能顯示的圖像)。

在上面的例子中,我們的控制器要求模型和模型直接觸發事件,這是在控制器的線程內,這很好,因爲沒有併發訪問的風險(同一個線程=沒有問題),但是:

如果登錄是遠程登錄(例如在線服務認證),我們將敲打服務器的門並等待其答案。由於這個過程可能需要幾秒鐘,控制器會一直等待服務器的答案。爲了避免這種情況,我們應該將請求發送到另一個線程,並使用消息(等待服務器)修改視圖,直到我們從服務器獲得答案。一旦我們得到答案(或者在超時後如果沒有答案),我們之前創建的線程將得到模型的答案爲真或假。一個非常糟糕的想法是直接用結果更新視圖。問題是獲得答案的線程沒有進入主控制器的線程,因此如果我們更新視圖,我們確實面臨併發訪問(如果視圖對象由2個線程完全改變爲同一時間遇到碰撞)。確保我們不會干擾主線程的一種方法是簡單地通過將在主事件循環中調度的通知將模型的答案發送到主線程。在這種情況下,我將使用通知中心,而不是模型中的簡單廣播。有意思的是,一些框架正在主事件循環內提供廣播。使用block或lambda函數有更好的解決方案,但它不在這個問題的範圍之內。

總結:

  • 無論是觀點還是模型應該知道控制器
  • 只有控制器做他們兩人知道
  • 注意他們都互相交談,使用方法聽衆或通知,如果同一型號有多個控制器。
  • 的過程總是如下:
    • 控制器創建視圖,並聽取其
    • 的觀點告訴控制器的動作發生
    • 控制器過程中的作用可能會問模型改變一些東西
    • 該模型給出了結果(通過聽衆或回調函數返回函數)
    • 控制器處理結果
    • 控制器用結果更新視圖。