[英]Is ActionListener in controller for Java GUI App good idea?
我不想嘗試遵循MVC模式。 在互聯網上,我看到最着名的例子是計算器,例如這里 。 我開始使用這種MVC模式的實現。 但是現在我對控制器中的動作監聽器有些疑慮,因為它們傾向於查看。
有很多變化與視圖相關的主要原因 - 字體,顏色,邊框等。此外還有僅僅修改視圖的actionlisteners! 因此,在控制器中實現這樣的actionlistener要困難得多(與視圖中的簡單內部匿名類相比)。 此外,它需要從控制器訪問許多視圖元素。
我有一個想法,在控制器和一些視圖中保留一些actionlisteners,但它可能導致將來混亂。 所以我想聽聽其他人的想法。
PS這個問題與許多ActionListener的MVC模式不重復
MVC不是一種“嚴格”的模式。 對原始模式有不同的解釋,並且經常使用不同的衍生物,如MVP或MVVM (即使人們說他們使用的是MVC)。
最重要的方面是將模型和視圖分開。 但有關它們如何連接的詳細信息可能會有所不同,具體取決於應用案例。
MVC模式最常出現的問題是: “什么是控制器?”
答案:
“獲得晉升的會計師”
根據我的個人經驗,很少有理由有一個明確的 “控制器”課程。 強制在一個“控制器”類中累積和匯總監聽器有幾個嚴重的缺點。 為了在GUI組件和Model之間建立連接,您有兩個選擇:一個選項是允許訪問視圖組件以附加偵聽器:
gui.getSomeButton().addActionListener(myActionListener);
我認為這是一個禁忌,因為它暴露了實現細節並阻礙了修改。 另一種選擇更好 - 即提供允許附加偵聽器的方法:
gui.addActionListenerToSomeButton(myActionListener);
但我認為這是值得懷疑的,因為它仍然暴露了一個按鈕的事實。 例如,當您有一個JTextField
輸入一個數字,然后將其更改為JSlider
時,問題可能會變得更加明顯:它將更改所需的Listener類型,盡管它應該只是視圖的問題。
在Swing應用程序中,我認為Listener可以被視為“小控制器”。 我認為擁有直接調用模型方法的匿名監聽器是完全可行的(除非有這些調用的附加邏輯)。
話雖如此:我不會考慮您作為MVC的“好”示例鏈接的示例。 首先,因為所選示例沒有顯示MVC的關鍵點:模型不包含狀態 ,並且MVC中的模型通常是必須被觀察的事實(因此,作為Listeners附加)不清楚。 其次,由於上面提到的要點,因此建立GUI與模型之間的連接的方式是有問題的。
我喜歡http://csis.pace.edu/~bergin/mvc/mvcgui.html上的例子。 它的一部分也可能受到質疑(例如,使用通用的Observer / Observable類),但我認為它以令人信服的方式很好地展示了MVC的基本概念。
編輯 :沒有以ZIP的形式下載此示例。 但您可以將TemperatureModel
, TemperatureGUI
, FarenheitGUI
和MVCTempConvert
復制並粘貼到IDE中。 (它假定存在CelsiusGUI
。此CelsiusGUI
,在網站上省略,但在結構上等於Farenheit GUI。對於第一個測試,實例化它的行可能只是被注釋掉)。
添加偵聽器的選項在此示例中由抽象的TemperatureGUI
類提供。 實際的偵聽器由具體的 FarenheitGUI
類創建和附加。 但這或多或少是一個實現細節。 這里的關鍵點(也是針對原始問題)是監聽器是由View 創建的,以內部類甚至匿名類的形式。 這些偵聽器直接調用模型的方法。 即,將溫度設置為Farenheit(用於Farenheit GUI),或設置以攝氏度為單位的溫度(對於Celsius GUI)。
仍有一定程度的自由。 它不是一個“完美”或“通用”的MVC示例。 但是,到目前為止,我發現的恕我直言比其他大多數MVC更好,因為它很好地展示了重要的方面:
Observable
Observer
在更復雜的常規設置中,不會使用Observable
/ Observer
類。 相反,人們可以為模型創建專用的偵聽器和可能的事件。 在這種情況下,這可能類似於TemperatureChangedListener
和TemperatureChangedEvent
。 為簡潔起見,此處使用了Observable
/ Observer
類,因為它們已經是標准API的一部分。
Agin,請注意可能存在更復雜的應用案例,其中在這個小例子中概述的MVC的想法必須稍微擴展。 特別是,當有要進行超越模型只是調用方法任務。 例如,當View包含多個輸入字段時,在將數據傳遞給模型之前必須對其進行預處理或以其他方式驗證。 這樣的任務不應該由匿名聽眾完成。 相反,這些任務可以在一個類中概括, 然后可以稱為“控制器”。 但是, 將實際偵聽器附加到GUI組件仍然只能通過View完成。 作為一個過於暗示的例子:這可能會發生
// In the view:
someButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
String s = someTextField.getText();
Date d = someFormattedTextField.getDate();
int i = someSlider.getValue();
// The controller validates the given input, and
// eventually calls some methods on the Model,
// possibly using the given input values
controller.process(s, i, d);
}
});
我通常遵循以下設計模式,它對我很有效,因為它可以非常有效地分離模型視圖和控制器
視圖 :您的視圖應包含所有jcomponents及其getter或setter,組件放置相關代碼,布局相關代碼。 我從不向視圖類中的任何組件添加任何偵聽器,它只處理布局
模型 :模型應該有占位符來保存視圖的數據,例如:如果你有一個JTable,模型可能包含一個arraylist,它將保存你的JTable的數據
Controller = Model + view(這里是你將模型與視圖綁定的地方)在這里添加所有的監聽器綁定你的文本字段,組合框等添加你的客戶端業務邏輯為你的按鈕添加你的動作監聽器這是你應該訪問你的視圖的地方和模型。
希望這可以幫助。
如果遵循Controller GRASP模式 (假定您分離了接口層和域層),則actionPerformed()
代碼將保留在接口層中。 書中解釋了這個概念 ,但為了清楚起見,我在本書的教師資源中加入了一個圖:
編輯:正如我在上面的評論中所說,如果您實施不同的視圖(例如,在移動應用上,或添加語音識別),您希望保持發送到您的域層的相同系統操作。 對我而言,我喜歡視圖層“識別轉換為控制器命令的用戶手勢”的概念。
所有邏輯都應放在控制器中。 然而,沒有嚴格的線,一些非常簡單的邏輯可以在視圖中很好。 將actionListeners放在控制器中,然后在GUI中放置按鈕。 這就是我通常做的事情。 有時我很懶,讓我的按鈕實現actionListeners讓他們自己聽,在這種情況下我把按鈕放在控制器包里。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.