2011-04-27 75 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