2011-04-27 48 views
1

我經常使用Martin Fowler的Presentation Model模式實現我的Java swing GUI。Clojure defrecord和私有字段

下面是一個例子:

import java.awt.BorderLayout; 
import java.awt.event.ActionListener; 
import javax.swing.BorderFactory; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JList; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.ListModel; 

interface MainView { 
    void configurationButtonAddActionListener(ActionListener actionListener); 

    void directoryLabelSetText(String text); 

    ListModel fileListGetModel(); 

    void setVisible(final boolean visible); 
} 

class MainFrame 
     extends JFrame 
     implements MainView { 
    private final JButton configurationButton = new JButton("Configuration..."); 
    private final JLabel directoryLabel = new JLabel(); 
    private final JList fileList = new JList(); 

    public MainFrame(final String title) { 
     super(title); 

     final JPanel mainPanel = new JPanel(new BorderLayout()); 
     add(mainPanel); 
     mainPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12)); 

     mainPanel.add(directoryLabel, BorderLayout.NORTH); 
     mainPanel.add(new JScrollPane(fileList)); 
     mainPanel.add(configurationButton, BorderLayout.SOUTH); 

     setSize(800, 600); 
     setLocationRelativeTo(null); 
    } 

    @Override 
    public void configurationButtonAddActionListener(final ActionListener actionListener) { 
     configurationButton.addActionListener(actionListener); 
    } 

    @Override 
    public void directoryLabelSetText(final String text) { 
     directoryLabel.setText(text); 
    } 

    @Override 
    public ListModel fileListGetModel() { 
     return fileList.getModel(); 
    } 
} 

的接口可以然後被傳遞到呈現器類,它是負責處理在視圖上的所有動作。模擬版本可以傳遞給演示者進行測試,並且視圖非常簡單,理論上它不需要進行單元測試。

我試圖用defrecord做Clojure中類似的事情:

(ns mainframe 
(:gen-class) 
(:import 
    [java.awt BorderLayout] 
    [javax.swing JButton JFrame JLabel JList JPanel JScrollPane])) 

(if *compile-files* 
    (set! *warn-on-reflection* true)) 

(defprotocol MainView 
    (directory-label-set-text [this text]) 
    (set-visible [this visible])) 

(defrecord mainframe [^JFrame frame 
         directory-label 
         file-list 
         configuration-button] 
    MainView 
    (directory-label-set-text [this text] 
    (.setText directory-label text)) 
    (set-visible [this visible] 
    (.setVisible frame visible))) 

(defn create-main-frame 
    [title] 
    (let [directory-label (JLabel.) 

     file-list (JList.) 

     configuration-button (JButton. "Configuration...") 

     main-panel (doto (JPanel. (BorderLayout.)) 
        (.add directory-label BorderLayout/NORTH) 
        (.add (JScrollPane. file-list)) 
        (.add configuration-button BorderLayout/SOUTH)) 

     frame (doto (JFrame.) 
       (.setTitle title) 
       (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE) 
       (.add main-panel) 
       (.setSize 800 600) 
       (.setLocationRelativeTo nil))] 
    (mainframe. frame directory-label file-list configuration-button))) 

的只有我能了做界面和「階級」的方式使用defprotocoldefrecord。有沒有更好的辦法?有什麼辦法可以使defrecord中的「字段」包含組件(JButton,JLabel,JList)爲私有的?我不喜歡公開實現細節。

回答

3

對於這些實現你可能需要的東西deftype而不是defrecorddefrecord更多關於數據,而deftype用於實現某些接口背後的本質。我知道這聽起來有點模糊,但這是我對http://clojure.org/datatypes的解釋。我認爲你的框架屬於第二類。

我不會花太多時間試圖隱藏東西。不要觸摸類型字段(除非在接口函數內部)。只使用接口函數與類型進行交互。那麼這個領域在技術上是私人的還是公共的並不重要。 (再次:參考http://clojure.org/datatypes,關於意見的部分)

+0

deftype和defrecord之間的主要區別之一是defrecord會自動爲您提供equals()和java.lang.Comparable(IIRC)的默認實現,如果您試圖實現一種新的數據類型。另一方面,deftype給你一個完全空白的對象。 – jmibanez 2013-01-09 00:01:35