1. 程式人生 > >JAVA 從SWING的Model 初探MVC思想

JAVA 從SWING的Model 初探MVC思想

最近嘗試寫一個記賬的專案來鞏固JAVASE的知識,順便學習真正的專案該如何一點點構建,看了個類似的專案叫一本糊塗賬,來自 http://how2j.cn/k/hutubill ,因為沒有認真看過swing的知識,所以在用到ComboBox和Table的時候對於ComboBoxModel和TableModel這兩個需要寫的model有些疑惑。

因為是GUI,又有Model,我就很自覺的想:這個是不是就是天天說的MVC模式?於是google了一下,果然,SWING是MVC的方式寫的。我目前的理解是,建一個JTable必須指定一個專門的TableModel來規定該Table的顯示時的內部邏輯和規則,TableModel這個介面定義了:

public getColumnCount() //得到列數的規則
public Object getValueAt(int rowIndex, int columnIndex) //得到指定位置的值的規則
public int getRowCount()//得到行數的規則

這個規則是邏輯行為,而JTable創建出來之後,只能按照這個邏輯行為對user進行展示,按照這個發展,Swing的Controller應該是在和View糅合在一起了,畢竟使用者跟UI互動的時候又想有業務,又想有介面顯示,很難區分。只有把View中的UI和Listener繫結的過程,使得點選某個UI如提交表單時,可以呼叫相應的Listener這個環節屬於Controller吧,我覺得Listener應該不屬於Controller,因為Controller應該不涉及對Model具體的調整;UI自然也有View層,它根據Model把內容顯示出來。Controller和View都是一些基於Model的方法,沒有任何狀態!

暫時是這樣理解的…

找了很多帖子,明天早上上完課認真看一下,中午再更新。未完待續。

按照上述思路MVC層實現

https://blog.csdn.net/YoutellIdo/article/details/48145755
TestModel.java

package model;

public class TestModel {
    private String message;

    public String getMessage(){
        return message;
    }
    public void setMessage(String message)
{ this.message=message; } }

TestView.java

package view;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class TestView extends JPanel{
    private static final long serialVersionUID = 1L;
    private JTextArea textArea;
    private List<ActionListener> listeners;
    public void addActionListener(ActionListener actionlistener){
        listeners.add(actionlistener);
    }
    public void setTextArea(String text){
        textArea.setText(text);
    }

    public TestView() {
        listeners=new ArrayList<ActionListener>();
        setLayout(null);
        textArea=new JTextArea();
        textArea.setBounds(20, 20, 400, 100);
        add(textArea);
        JButton textbtn=new JButton("Show Message");
        textbtn.setBounds(120, 140, 150, 40);
        add(textbtn);
        textbtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                for(int i=0;i<listeners.size();++i){
                    listeners.get(i).actionPerformed(e);
                }
            }
        });
    }
}

TestController.java

package controller;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;

import model.TestModel;
import view.TestView;

public class TestController {
    private TestView testview;
    private TestModel testmodel;

    public TestController() {
        testview=new TestView();
        testmodel=new TestModel();
        testview.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("suc...");
                testmodel.setMessage("test...");
                testview.setTextArea(testmodel.getMessage());
            }
        });

    }
    public JPanel getView(){
        return testview;
    }

    public static void main(String[] args) {
        TestController testcontroller=new TestController();
        JFrame frame=new JFrame("TEST");
        frame.setLayout(new BorderLayout());
        frame.setBounds(100, 100, 450, 300);
        frame.getContentPane().add(testcontroller.getView());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        }
 }

Listener到底屬於哪裡呢???

這樣分層應該是針對Swing目前的設計的MVC了,不過我覺得很奇怪,看了一些別人文章,說永遠不應該把UI和Listener在View層中分離,不然UI元件就被暴露在外。那麼

StackOverFlow大法好:

原文這樣說到,
"Another issue is, you really don’t want to expose UI components to anybody, the controller shouldn’t care how certain actions occur, only that they can.

This would suggest that the ActionListeners attached to your UI controls should be maintained by the view. The view should then alert the controller that some kind of action has occurred. For this, you could use another ActionListener, managed by the view, to which the controller subscribes to."

在這個stackoverflow中的高贊答案中他其實給View層設定了一個介面,該檢視將實現一個介面(描述控制器和檢視的contact),允許控制器管理它。控制器將向檢視註冊介面(Listener),以允許在檢視中發生某些事件時通知它。該檢視將管理它自己的內部事件託管(例如ActionListener),意思就是說實際的Listener還是在View層裡,但是是通過Controller來管理的,通過控制器/檢視Listener介面,告訴控制器發生了什麼事情,這將控制器和檢視相互分離…

這裡,Controller應該控制View,但是為了讓View自己管理自己的具體控制元件該有什麼Listener,View中反而有了一些Controller例項,把View註冊給Controller,然後讓Controller中的控制方法去呼叫View中的具體方法…應該是這個意思。
這樣只是探討怎麼把Swing裡的View和Controller層分離。。說實話分了還不如不分,因為GUI就是這樣的特性。所以Swing其實並不是標準的MVC設計,應該叫M +VC,VC揉和在一起…所以剛開始看了一堆從Swing學習MVC的文章,真搞不明白他們為什麼非要從Swing開始學。。

上面這兩個例子很長,就不貼上來了,有興趣的直接看

Java and GUI - Where do ActionListeners belong according to MVC pattern?
https://stackoverflow.com/questions/26517856/java-and-gui-where-do-actionlisteners-belong-according-to-mvc-pattern

對MVC本身

經過這些小小的探索和梳理,我覺得MVC這個模式也有一定侷限,首先對Model的理解更深了,Model其實就應該是數學建模大賽裡所謂的“模型”,這些東西就應該抽象成這個樣子,應該是一個一個的JavaBean;所謂View就是怎麼展示這些Model,Controller就是使用者和View互動的時候,View會通知Controller,Controller再去操作Model層,Controller只是把Model和View跟分離開,然後分別通訊,View和Model本身不通訊,所以顯然Swing不是純粹的MVC,正常的開發中View跟Model沒少通訊。然後只有Model真正描述了資料也好,模型也好;Controller和View都是一些操作它的方法。

我還沒做過真正的Web專案,目前對Servlet、JSP、DAO、Server還未深刻體驗,所以體會不是很深。給出一些關於Web分析的文章,寒假計劃開始學習Spring做Web專案,到時候應該會再更一篇。
貼出我看的一些覺得有用的帖子給大家:
FAQ-如何理解 MVC 中的 Model?
https://www.zhihu.com/question/22886622
JavaWeb中的MVC https://blog.csdn.net/weixin_41667774/article/details/79278605
Swing元件中的Model詳解,這裡提到了Swing是Model-Driven,不是MVC
http://www.52im.net/thread-39-1-1.html
通過Java Swing看透MVC設計模式
http://developer.51cto.com/art/200612/37079.htm

下面這篇我還沒看,計劃吃完午飯好好看一下,
Learn to make a MVC application with Swing and Java 8
https://www.ssaurel.com/blog/learn-to-make-a-mvc-application-with-swing-and-java-8/