【问题标题】:is this swing tablemodel code badly designed?这个摇摆桌模型代码设计得很糟糕吗?
【发布时间】:2012-02-07 11:34:16
【问题描述】:

上下文:我有一个基于 clojure 的填字游戏应用程序,其主要 ui 是一个带有两个选项卡、一个网格和一个线索表的 JTabbedPane。线索表是线索向量的视图,但向量本身不是数据的权威存储,而是通过(active-cluelist) 函数从几个内部数据结构动态生成的,由选择的线索选项卡触发。

所以这是线索表的实现:

(def cluelist [])
(def update-cluelist)
(def model)

(defn make []
  (let [column-names ["Sq" "Word" "Clue"]
        column-widths [48 200 600]
        table-model (proxy [AbstractTableModel] []
                      (getColumnCount [] (count column-names))
                      (getRowCount [] (count cluelist))
                      (isCellEditable [row col] (= col 2))
                      (getColumnName [col] (nth column-names col))
                      (getValueAt [row col] (get-in cluelist [row col]))
                      (setValueAt [s row col]
                                  (let [word (get-in cluelist [row 1])]
                                    (add-clue word s) ; editing a cell updates the main clue data
                                    (def cluelist (assoc-in cluelist [row 2] s))
                                    (. this fireTableCellUpdated row col))))
        table (JTable. table-model)
        ]

; some pure display stuff elided

(def model table-model)
)

(defn update-cluelist []
  (def cluelist (active-cluelist))
  (.fireTableDataChanged model))

在另一个讨论中有人指出,手动调用fireTableDataChanged(update-cluelist) 的主要代码异味,因为 TableModel 类之外的任何东西都不应该调用该方法。但是,我觉得这是表是从外部源动态生成的不可避免的结果。文档不是很有帮助 - 他们声明

您的自定义类只需要调用以下之一 AbstractTableModel 方法每次表数据由一个更改 外部来源。

这隐含地假定 CustomTableModel 类是数据的权威来源。

这里还有一些 clojure/java 阻抗不匹配 - 在 java 中,cluelistupdate-cluelist 是我的 TableModel 的私有成员和方法,而在 clojure cluelist 和表模型中是update-cluelist 可以访问的动态范围变量。

我的主要问题是没有很多 clojure/swing 代码可供我寻找最佳实践。有人对最好的方法有什么建议吗?

【问题讨论】:

  • kleopatra:是的 :) 感谢您让我重新检查设计!

标签: swing clojure


【解决方案1】:

建议:使用原子作为线索列表。不断重新定义线索列表并不是表示可变数据的正确方法。老实说,我希望它在您第二次定义线索列表时抛出异常。

如果您使用原子作为线索列表,您可以从观察者调用fireTableDataChanged 方法,而不是手动调用它。这意味着无论何时(在任何地方)您更改原子,fireTableDataChanged 都会被自动调用,无需显式调用。

def 的问题是多次调用def 在多线程环境中效果不佳,Clojure 试图使所有内容都默认为相当线程安全的。据我了解,使用 var 的“正确”方式是不理会它的根绑定(即,不要再次调用 def),如果需要在本地更改它,请使用 bindingdef 可能会按照您使用它的方式工作,但是该语言设置为在这种情况下支持原子、引用或代理,并且这些可能在大多数情况下会更好地工作(即您有观察者)。此外,如果您稍后添加线程,您完全不必担心线程。

【讨论】:

  • 原子绝对看起来是个好主意,因为正如你所注意到的,我可以向它添加一个观察者,但为什么 var 是错误的?我已经看到在 clojure 代码中经常使用 var 来存储不需要并发写入的“可变”数据结构。
  • @MartinDeMello 查看扩展答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-13
  • 2012-09-06
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多