dimanche 19 septembre 2010

Rétro-conception de Design Patterns java

Objectif

être capable de retrouver des Design Patterns éprouvés dans des classes Java.

Intérêt

Même si de nos jours les outils de rétro-conception savent très bien passer de classes java à des diagrammes UML, un pas supplémentaire peut être fait en retrouvant les Design Patterns noyés anonymement dans des schémas. Un niveau d'abstraction supplémentaire serait donc le bienvenu.

Bonnet blanc et blanc bonnet

Il existe en fait de nombreuses façons de concevoir ces Design Patterns, avec des variantes mineures, qui font tout le charme des algorithmes visant à retrouver les 3 types de DP ( construction, structuration, comportement ). Un groupe connu sous le nom de "bande des quatre" ( Gang of four en Anglais ) est cité sur le site de SUN comme étant le premier à s'être penché sur le problème.
Cependant, l'expérience a prouvé que les concepteurs de SUN n'avaient pas toujours suivi ces bonnes pratiques standard.

Cas du Pattern "Singleton"

Il nécessite :
  • un constructeur privé
  • une méthode d'instance
  • un attribut d'instance

Exemple du pattern Singleton :

public class Singleton
{
    /** Récupère l'instance unique de la class Singleton.<p>
     * Remarque : le constructeur est rendu inaccessible
     */
    //---------------------------------------------  
    public static Singleton getInstance()
    {
        if (null == instance)
        { // Premier appel
            instance = new Singleton();
        }
        return instance;
    }
    //---------------------------------------------
    /** Constructeur redéfini comme étant privé pour interdire
     * son appel et forcer à passer par la méthode <link
     */
    private Singleton()
    {
    }
    //---------------------------------------------
    /** L'instance statique */
    private static Singleton instance;
    //---------------------------------------------
}

Exemple de code pour le détecter :

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class CheckSingleton
{
    boolean debug = false ;
    //---------------------------------------------
    public CheckSingleton( String _className )
    {
        traiter(_className) ;
    }
    //---------------------------------------------
    boolean hasNoPublicConstructor ( Class _c )
    {
        boolean b = false ;
        Constructor[] publicConstructeurs = _c.getConstructors();
        if ( publicConstructeurs.length == 0 )
        {
            b = true ;
            if ( debug )
                System.out.println( "hasNoPublicConstructor" ) ;
        }
        return b ;
    }
    //---------------------------------------------
    boolean hasSomePrivateConstructor ( Class _c )
    {
        boolean b = false ;
        Constructor[] tousConstructeurs = _c.getDeclaredConstructors();
        for ( Constructor unConstructeur : tousConstructeurs )
        {
            String name = unConstructeur.getName();
            int m = unConstructeur.getModifiers() ;
            if ( Modifier.isPrivate(m) )
            {
                b = true ;
                if ( debug )
                    System.out.println( "hasSomePrivateConstructor" ) ;
            }
        }
        return b ;
    }
    //---------------------------------------------
    boolean hasSomePublicStaticDedicatedMethod ( Class _c )
    {
        boolean b = false ;
        Method [] publicMethods = _c.getMethods() ;
        for ( Method uneMethode : publicMethods )
        {
            String type = uneMethode.getReturnType().getName() ;
            int m = uneMethode.getModifiers() ;
            if (
                    ( Modifier.isPublic(m) )
                    && ( Modifier.isStatic(m) )
                    && ( _c.getName().compareTo(type) == 0 )
            )
            {
                b = true ;
                if ( debug )
                    System.out.println( "hasSomeDedicatedMethod" ) ;
            }
        }
        return b ;
    }
    //---------------------------------------------
    boolean hasSomePrivateStaticDedicatedProperty( Class _c )
    {
        boolean b = false ;
        Field [] tousChamps = _c.getDeclaredFields() ;
        for ( Field unAttribut : tousChamps )
        {
            int m = unAttribut.getModifiers() ;
            String type = unAttribut.getType().toString() ;
            type = type.replace("class ", "") ;
            //System.out.println( "type=" + type ) ;
            if (
                    (Modifier.isPrivate(m))
                    && (Modifier.isStatic(m))
                    && ( _c.getName().compareTo(type) == 0 )
            )
            {
                b = true ;
                if ( debug )
                    System.out.println( "hasSomeDedicatedProperty" ) ;
            }
        }
        return b ;
    }
    //---------------------------------------------
    void traiter ( String _className )
    {
        //System.out.println( "..." ) ;
        try
        {
            Class c = Class.forName(_className);

            if     (
                    hasNoPublicConstructor(c)
                    && hasSomePrivateConstructor(c)
                    && hasSomePublicStaticDedicatedMethod(c)
                    && hasSomePrivateStaticDedicatedProperty(c)
            )
            {
                System.out.println( "Singleton" ) ;
                System.out.println( " classe        : " + _className ) ;
            }
        }          
        catch (LinkageError ee)
        {
            System.out.println("pb pour traiter : " + _className );
        }
        catch (ClassNotFoundException e)
        {
            System.out.println("pb pour traiter : " + _className );
        }
    }
    //---------------------------------------------
}

Cas déjà traités

  • Singleton
  • Proxy ( avec variantes )
  • Observateur

Pour approfondir le sujet

jeudi 16 septembre 2010

Comment récupérer les types Jdbc et leurs libellés correspondants ?

Objectif

ne plus coder en dur dans des programmes des tableaux correspondants aux types Jdbc à traiter, mais les récupérer directement depuis la classe "java.sql.Types"

Solution

import java.lang.reflect.Field;
import java.util.Hashtable;

public class GetJdbcTypes
{
// ---------------------------------------------
Hashtable<Integer,String> lesTypes = new Hashtable<Integer,String>() ;
// ---------------------------------------------
public GetJdbcTypes() throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
Class c = Class.forName("java.sql.Types");
Field[] f = c.getFields();
for(int i=0;i<f.length;++i)
{
String lib = f[i].getName() ;
Integer ii = (Integer) f[i].get(c) ;
lesTypes.put(ii, lib) ;
System.out.println( lib + " = " + ii ) ;
}
}
// ---------------------------------------------
public static void main(java.lang.String[] args)
{
try
{
GetJdbcTypes appli = new GetJdbcTypes() ;
System.out.println( "nb = " + appli.lesTypes.size() ) ;
}
catch(Exception e)
{
e.printStackTrace();
}
}
// ---------------------------------------------
}

Résultat généré

BIT = -7
TINYINT = -6
...
NCLOB = 2011
SQLXML = 2009
nb = 36

Commentaires

  • le nombre de valeurs dépend de la version java, une vingtaine en jdk 1.4, 36 en jdk 6.
  • la classe ne contient que des entiers, pas besoin de complexifier ce traitement simple.

Pour approfondir le sujet