vendredi 3 décembre 2010

Créer des GUI en Swing totalement découplés par Spring IoC

Les possibiltés offertes par le Framework Spring dans le cadre de développement des applications Swing sont peut mises en évidence, comparaiment à celles du web. Que ce qu'offre Spring dans ce contexte ? Nous allons dans ce tutoriel voir un exemple concret étape par étape, et ainsi en déduire notre conclusion.
Jetons un coup d'oeil  sur la structure finale de notre application :


Comme vous pouvez le constater nous utilisons la bibliothèque spring-2.5.jar que vous pouvez télécharger depuis le site web : www.springsource.org, ainsi que commons-loggin.jar qui va servir pour les logs. Notez aussi l’existence de quelques composants Swing ordinaires tel que : JButton, JTextField, JPanel et bien sûr JFrame, nous avons aussi un ActionListener qui va être ajouté à notre bouton. Chacune des classes commençant par My hérite d'un composant Swing, donc rien de spécial, sauf les deux fichiers SpringLauncher.java qui va servir pour lancer notre application en utilisant des classes spécifique à Spring en appelant le fichier de configuration app-context.xml. Au démarrage notre application aura l’aspect suivant :


C'est un résultat pertinent. Les composant Swing ne font aucune chose de spécial. Le point ici est d'ajouter tout simplement des composant Swing à l'application sans ajouter aucun code java le rendant possible. Normalement à l’absence de Spring sa doit être fait avec du code Java, en ajoutant le JPanel à JFrame à l'aide de la méthode add,  et d'ajouter JButton, JTextField au JPanel de la même manière. Dans notre cas nous ne procéderons pas ainsi. En fait aucune classe n’appellera l'autre, elles sont toutes indépendant, elles sont découplées, dont voici le code de MyJFrame :



package springSwinging;
import java.awt.Dimension;
import javax.swing.JFrame;
/**
 *
 * @author Arafat Bouchafra
 * @Date   2 déc. 2010
 * @Time   03:00:34
 */
public class MyJFrame extends JFrame {
    public void init() {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
                setSize(new Dimension(300, 300));
                setVisible(true);
            }
        });
    }
}


Les autres classes sont similaires, ne délivrons que le code spécifique à chaque composant Swing définissant. L’évènement ActionListener est découplé, l'ActionListener n'est pas ajouté à JButton dans le code Java de la classe ci-dessous. toutes les classes sont isolées, séparées, et rendues indépendantes.


Ceci est possible grâce à la présence des JARs Spring dans la classpath, ensembles(les JARs) avec la classe SpringLauncher.java qui cherche le fichier de configuration Spring app-context.xml qui définie comme suite :




Après les six premières lignes, qui sont l'en-tête de notre fichier de configuration, voici la description détaillée de chaque élément:


Lignes 8-15: définisses la classe MyJFrame, en spécifiant sa propriété"title" et sa propriété "contentPane". Notez la définition de l'attribut "init-method", dont la valeur est le nom la méthode "init" de la classe MyJFrame que nous utiliserons pour l'instanciation de la classe.


Lignes 17-26 Définisse le mainPanel, qui va contenir deux JTextField et une autre instance de lui nommée buttonPanel, définie dans les lignes 28-35. Nous fixons aussi la propriété nommée "axis" et  la propriété nommée "panelComponents". Les deux panels sont construits à partir de la classe JPanel. Le premier d'entre eux est utilisé afin de définir sa propriété "axis" du layout utilisé par la classes MyJPanel qui un BoxLayout. En revanche la propriété "panelComponents" va être remplié par nos trois composant Swing à savoir les deux JTextField et le buttonPanel. Un iterator dans la classe MyJPanel va bouclé autour des composant reçu, en les y ajoutant. Tout ça aura lieu dans la méthode "init", qui est définie comme valeur de l'attribut "init-method".


Lignes 28-35: Définisses le panel du bas qui contient seulement la classes MyJButton. Notez que ce panel est définit par la même classes définissant le mainPanel. Donc nous réutilisons la classe MyJPanel par le biais du fichier de configuration Spring.


Ligne 37Définie le premier JTextField.
Ligne 38: Définie le deuxième JTextField.


Lignes 40-47: Définisses  le JButton, avec ses deux propriétés  "text" et "actionListener". Notez que nous n'avons pas définit les propriétés "text" des JTextFields que nous pouvons le faire. Vous pouvez définir la propriété "text" et les autres dans le fichier de configuration Spring,le choix est le votre.


Ligne 49: Définie l'ActionListener.


Voici le fichier de configuration complet qui est facile à lire, pas de grandes surprises. Maintenant voyant à quoi ces classes ressembles exactement. Le code source de la classe MyJFrame a été montrer ci-haut. voici le code source des autres classes :



package springSwinging;
import java.awt.Component;
import java.util.Iterator;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
/**
 *
 * @author Arafat Bouchafra
 * @Date   2 déc. 2010
 * @Time   03:09:26
 */
public class MyJPanel extends JPanel {
    private List panelComponents;
    private int axis;
    public void setAxis(int axis) {
        this.axis = axis;
    }


    public void setPanelComponents(List panelComponents) {
        this.panelComponents = panelComponents;
    }


    public void init() {
        setLayout(new BoxLayout(this, axis));
        for (Iterator iter = panelComponents.iterator(); iter.hasNext();) {
            Component component = (Component) iter.next();
            add(component);
        }
    }
}

package springSwinging;
import javax.swing.JTextField;
/**
 *
 * @author Arafat Bouchafra
 * @Date   2 déc. 2010
 * @Time   03:10:58
 */
public class MyJTextField extends JTextField {
    public void init() {
        setText("hello world");
    }
}

package springSwinging;
import java.awt.event.ActionListener;
import javax.swing.JButton;
/**
 *
 * @author Arafat Bouchafra
 * @Date   2 déc. 2010
 * @Time   03:11:32
 */
public class MyJButton extends JButton {
    private ActionListener actionListener;
    public void setActionListener(ActionListener actionListener) {
        this.actionListener = actionListener;
    }

    public void init() {
        this.addActionListener(actionListener);
    }
}

package springSwinging;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;
/**
 *
 * @author Arafat Bouchafra
 * @Date   2 déc. 2010
 * @Time   03:12:22
 */
public class MyActionListener implements ActionListener {

    public void actionPerformed(ActionEvent e) {
        JOptionPane.showMessageDialog(null, "Hello from Spring!");
    }
}

Nous avons ajouté un ActionListener à MyJButton, mais nous n'avons pas spécifié lequel. Pour changer l'ActionListener, modifiez seulement la ligne 49 du fichier de configuration Spring. Changez seulement l'attribut "classname" vers un autre ActionListener que vous devez définir. Clairement, il n'y a pas de code Java connectant la classe "MyActionListener" à la classe "MyJButton". Similairement, il n'y a pas de code Java connectant les composants Swing entre eux. De point de vue utilisateur final, il n'y a pas de difference. Mais de point de vue développeur, toutes les connexions entres les composants seront faites dans le fichier de configuration Spring, et voir même entre composants et leurs actions (MyJButton et MyActionListener) .

Finalement, jetons un coup d'oeil sur la classe SpringLauncher.java, qui utilise un code spécifique à Spring:

package springSwinging;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 *
 * @author Arafat Bouchafra
 * @Date   2 déc. 2010
 * @Time   03:12:59
 */
public class SpringLauncher {

    public static void main(String[] args) {
        String[] contextPaths = new String[]{"app-context.xml"};
        new ClassPathXmlApplicationContext(contextPaths);
    }
}

Maintenant, que est ce nous avons gagné? Est ce que Spring encourage vraiment une désintégration des composants Swing à ce bas niveau? Pas nécessairement , mais possible. Le point est, vous pouvez détacher autant que vous voulez. Tout dans la même application. Mais pourqoui faire ça ? Maintenant que nous avons compris le QUOI, allons voire le POURQUOI. Il y a pas mal de livre traitant le POURQUOI. le POURQUOI est "dependency injection [1]"(l'injection de dépendences) et "loose coupling" (Accouplement desserré(libre)). Un bon avantage est celui là, Parce que vos composants sont vraiment séparés l'un de l'autre,il est facile de les tester. Vos tests de JUNIT (ou d'autres tests) seront plus faciles à écrire parce qu'il n'y a aucune gêne d'une classe à une autre. Aussi, en ce qui concerne le code de plomberie, c'est-à-dire, le câblage(le wiring), que deviez-vous normalement maintenir(entretenir)? Tout cela est maintenu dans le fichier de configuration Spring; Aucun de cela n'est dans le code Java. Notez aussi que le fichier de configuration Spring est non-envahissant. Vous pouvez simplement le glisser dans une application existante, Écrivez un bean pour la classe principale et ajoutez ensuite le code du lanceur. Alors vous êtes bon pour  y aller. Ainsi, l'intégration avec vos applications Swing existantes peut arriver sans vous ayant besoin de changer ces classes existantes, à moins que vous ne vouliez faire, ça c'est une autre chose.

Finalement, regardant de nouveau notre JPanel. C'est un composant Swing réutilisable (comme les autres composants Swing utilisés ici, comme le JTextField, que vous avez réutilisé aussi). Vous l'avez utilisé deux fois dans la même application, pour des buts différents. A chaque fois, vous avez beaucoup de composant sur le layout du JPanel, depuis le fichier de configuration Spring, bien que vous utilisiez le même JPanel, son contenu pourrait être différent chaque fois vous le réutilisez. Encore, notez l'utilisation de la liste générique d'objets ici. Au lieu de spécifier un composant Swing particulier, qui aurait fait le JPanel moins réutilisable, nous avons opté pour une liste générique d'objets pour que nous ne serons pas limités par les composants qu'elle peut manipulée. Ce qu'il faut prendre en considération en créant des composants Swing détachés est, en travaillant d'une façon détachée a un impact sur votre processus de design.

J'espère que cela sert d'une introduction utile à Spring Framework dans le contexte de Swing.

Dans le prochain tutoriel, Nous allons utilisé un autre Framework de IoC, cette fois ci, il s'agit de Google Guice, nous allons introduire le principe de module.

N'hésitez pas à nous écrire, faire vos remarque ;-)


Aucun commentaire:

Enregistrer un commentaire