Question

Je mets en œuvre fréquemment mes interfaces graphiques swing Java en utilisant le modèle de Martin Fowler Présentation Modèle.

Voici un exemple:

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();
    }
}

L'interface peut alors être transmis à une classe de présentateur qui est responsable de traiter toutes les actions sur la vue. Une version maquette peut être transmis dans le présentateur pour tester et la vue est si simple que, en théorie, il n'a pas besoin d'être testé unitairement.

Je suis en train de faire quelque chose de similaire à l'aide Clojure defrecord:

(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)))

La seule façon que je peux avec faire l'interface et « classe » et utilisent defprotocol defrecord. Est-il possible de mieux? Est-il possible de faire les « champs » dans le defrecord qui contiennent les composants (JButton, JLabel, JList) privé? Je n'aime exposer les détails de mise en œuvre.

Était-ce utile?

La solution

Pour ce genre de mise en œuvre des choses que vous voulez probablement deftype au lieu de defrecord. defrecord est plus sur les données, alors que deftype est utilisé pour mettre en œuvre la débrouille derrière certaines interfaces. Cela semble un peu floue, je sais, mais il est mon interprétation de http://clojure.org/datatypes . Je pense que votre cadre tombe dans la deuxième catégorie.

Je ne passer trop de temps à essayer de choses cacher. Ne touchez pas les champs types (sauf à l'intérieur d'une fonction d'interface). Utilisez uniquement fonctions d'interface pour interagir avec le type. Ensuite, il n'a pas d'importance si le champ est techniquement privé ou public. (Encore une fois: voir http://clojure.org/datatypes , section sur avis)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top