IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

avec Java Discussion :

Factorisation de code


Sujet :

avec Java

  1. #1
    Membre régulier
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    133
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2012
    Messages : 133
    Points : 109
    Points
    109
    Par défaut Factorisation de code
    Voilà, j'aimerais factoriser une portion de code mais je ne vois pas comment faire.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    List<Mail> lstMail = new ArrayList<Mail>();
                List<Telephone> lstTel = new ArrayList<Telephone>();
                List<Tag> lstTags = new ArrayList<Tag>();
     
                for(String str : datasMail){
                    Mail m = new Mail(str);
                    lstMail.add(m);
                }
     
                for(String str : datasTel){
                    Telephone t = new Telephone(str);
                    lstTel.add(t);
                }
     
                for(String str : datasTags){
                    Tag tag = new Tag(str);
                    lstTags.add(tag);
                }
    Le problème est que la classe peut différer selon les foreach, soit un téléphone, un tag ou un mail, mais à part ça le code est sensiblement, non que dis-je, c'est le même.

    Comment puis-je faire ?

    Merci

  2. #2
    Membre actif Avatar de fastdeath124
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Août 2011
    Messages
    117
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Ingénieur sécurité

    Informations forums :
    Inscription : Août 2011
    Messages : 117
    Points : 200
    Points
    200
    Par défaut
    Les trois listes que t'es entrain de parcourir ont la même longueur ou ça peut différer?

  3. #3
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    Il y aurais moyen de factoriser cela en utilisant une méthode générique et un interface pour la transformation String->Object :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    	interface Builder<V,R> {
    		public R build(V value);
    	}
     
    	public static <P,V> List<V> transform(Collection<P> values, Builder<P,V> builder) {
    		List<V> result = new ArrayList<V>();
    		for (P value : values) {
    			result.add( builder.build(value) );
    		}
    		return result;
    	}
    Malheureusement cela implique l'utilisation d'une classe anonyme ce qui est assez lourd :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    		List<Mail> lstMail = transform(datasMail, new Builder<String, Mail>() {
    			@Override
    			public Mail build(String value) {
    				return new Mail(value);
    			}
    		});
            List<Telephone> lstTel = transform(datasTel, new Builder<String, Telephone>() {
    			@Override
    			public Telephone build(String value) {
    				return new Telephone(value);
    			}
    		});
            List<Tag> lstTags = transform(datasTags, new Builder<String, Tag>() {
    			@Override
    			public Tag build(String value) {
    				return new Tag(value);
    			}
    		});

    A la rigueur tu peux utiliser un attribut static final pour stocker la classe anonyme, ce qui sera plus pratique à utiliser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	List<Mail> lstMail = transform(datasMail, Mail.BUILDER);
            List<Telephone> lstTel = transform(datasTel, Telephone.BUILDER);
            List<Tag> lstTags = transform(datasTags, Tag.BUILDER);





    Une autre solution serait de passer par la reflection, même si cela peut entrainer un surcoût à l'exécution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    	public static <T> List<T> transform(Collection<String> values, Class<T> type) {
    		try {
    			Constructor<T> c = type.getConstructor(String.class);
    			List<T> result = new ArrayList<T>();
    			for (String value : values) {
    				result.add(c.newInstance(value));
    			}
    			return result;
    		} catch (Exception e) {
    			throw new RuntimeException("Reflection error", e);
    		}
    	}


    a++

  4. #4
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    Si tu n'en a que 3 types différents, laisse les ainsi, y a pas de raison de vouloir factoriser à outrance.
    Tu peux à la rigueur réduire tes foreach

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
                List<Mail> lstMail = new ArrayList<Mail>();
                List<Telephone> lstTel = new ArrayList<Telephone>();
                List<Tag> lstTags = new ArrayList<Tag>();
     
                for(String str : datasMail)
                    lstMail.add(new Mail(str));
     
                for(String str : datasTel)
                    lstTel.add(new Telephone(str));
     
                for(String str : datasTags)
                    lstTags.add(new Tag(str));
    Si t'en a vraiment beaucoup de types différent, tu peux éventuellement simplifier:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // manque la gestion des exceptions
    public List<T> convertString(Class<T> clazz,String... elements){
     List<T> result = new ArrayList<T>();
     Constructor<T> 	c = clazz.getConstructor(String.class);
     for (String s: elements)
        result.add(c.newInstance(s));
    }
    //....
                List<Mail> lstMail = convertString(Mail.class,dataMail);
                List<Telephone> lstTel =convertString(Tel.class,dataTel);
                List<Tag> lstTags = convertString(Tag.class,dataTag);
                //etc
    mais je ne suis pas fan. Plus propre, ce serait utiliser des factory, mais on tournera en boucle, on ne va pas factoriser des masses le code
    edit: comme adiguba donc

    Et tout ça n'aura d'intérêt que si l'instanciation n'est qu'une petit partie changeante dans la boucle et qu'il reste dans ta boucle des dizaines de lignes dupliquées à coté que tu ne nous as pas montré

  5. #5
    Membre régulier
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    133
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2012
    Messages : 133
    Points : 109
    Points
    109
    Par défaut
    Merci à tous pour vos réponses très rapides.
    Et bien pour l'instant j'en ai que 3, mais l'une des principales lignes de conduites de notre projet est de factoriser dans l'optique où un jour peut-être de nouvelles classe viendraient se rajouter. Et je me vois pas (ni l'utilisateur) créer un foreach pour chacune de ses classes.

    La solution de la réflection est celle que j'imaginais mais je ne connais pas ce concept de reflection, je vais esayer de mettre ça en place.

    Merci à vous !

    EDIT : Quand j'essaye de mettre en place la solution de reflection, j'ai un problème. Enfin plutôt je ne comprend pas de quel type est le deuxième paramètre de la fonction transform(), c'est à dire Class<T> type, que dois-je mettre en paramètre ? Une classe ? Il refuse. EDIT 2 : J'ai fais une boulette j'ai rien dit

  6. #6
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    La reflection est la solution la plus moche, celle d'adiguba avec le builder est la plus propre.

    En plus, je ne comprend pas ta logique du "Et je me vois pas (ni l'utilisateur) créer un foreach pour chacune de ses classes.". Ca prend deux ligne. Si l'utilisatuer est incapable de faire ça, ne lui donne pas accès au code

    Quand t'en aura une dixaine, tu pourra te dire "on factorise un peu ce code", et encore. Selon moi, il n'y a pas matière à factoriser ici: tu essaie de factoriser 1 ligne de code qui de toutes façons est différente à chaque fois. De plus, le code "factorisé" est plus gros que le code non factorisé: pour supprimer un foreach de 2 lignes, tu dois créer un builder de 3 lignes.

    Note, en "plus propre", il reste aussi la solution de l'enum

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package test.test;
     
    import java.util.ArrayList;
    import java.util.List;
     
    public enum DataType {
       MAIL { @Override  protected Mail transform(String item) {return new Mail(item);} }, 
       TEL  { @Override  protected Tel transform(String item) {return new Tel(item);} }, 
       TAG  { @Override  protected Tag transform(String item) {return new Tag(item);} };
     
     
     
       public <T> List<T> transform(String... items){
           ArrayList<T> o = new ArrayList<T>();
           for (String s: items)
               o.add(this.<T>transform(s));
           return o;
       }
       protected abstract <T> T transform(String item);
     
    }
    une nouvelle classe => une nouvelle entrée dans l'enum

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    	    List<Mail> mails= DataType.MAIL.transform(mailStrings);

  7. #7
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    je rajoute qu'un transformation simple dans une boucle => groovy sait faire ça en très peu de code, si ton client aime le groovy

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<Mail> lstMail = dataMail.collect{new Mail(it)}

  8. #8
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Note, en "plus propre", il reste aussi la solution de l'enum
    Ce n'est pas "plus propre"...
    Tu joues avec les Generics et le type de retour, mais cela te génère des warnings "unchecked" sur les méthodes transform() de tes enums...



    Cela peut paraitre insignifiant, mais en fait cela indique que le compilateur ne peut pas s'assurer de la cohérence des types.
    C'est dangereux car cela pourrait engendrer des erreurs inattendus plus loin.

    Par exemple avec le code suivant, qui pourrait être utilisé involontairement (un mauvais copier/coller est si vite arrive ) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<Mail> mails = DataType.TEL.transform(strings);
    En réalité on crée une List<Tel> qu'on affecte à une List<Mail>.
    Le problème c'est que ce code ne génère aucune erreur ni warning à la compilation, et qu'il s'exécute également sans problème !!!!

    Du coup on se retrouve avec une List<Mail> vérolée, qui risque de nous générer une ClassCastException n'importe quand.
    Et c'est très problématique car l'erreur peut survenir bien loin du code incriminé, ce qui peut engendrer des séances de débug vraiment affreuse !!!



    Les warning "unchecked" sont à éviter comme la peste.



    Si tu veux rester sur une solution proche, il serait préférable de passer par une classe abstraite et des champs static final :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    abstract class DataType<T> {
     
    	public static final DataType<Mail> MAIL = new DataType<Mail>() { @Override  protected Mail transform(String item) {return new Mail(item);} }; 
    	public static final DataType<Tel> TEL = new DataType<Tel>()  { @Override  protected Tel transform(String item) {return new Tel(item);} };
    	public static final DataType<Tag> TAG = new DataType<Tag>() { @Override  protected Tag transform(String item) {return new Tag(item);} };
     
    	public List<T> transform(String... items){
    		ArrayList<T> o = new ArrayList<T>();
    		for (String s: items)
    			o.add(this.transform(s));
    		return o;
    	}
     
    	protected abstract T transform(String item);
    }
    Là tu as un vérification du type par le compilateur, et un code type-safe




    a++

  9. #9
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Ce n'est pas "plus propre"...
    Désolé, j'entendais plus "propre" que la reflection Mais je suis entièrement d'accord avec toi. De toutes façons, toutes les solutions bouffent plus de code que le code qu'elles sont censée factoriser

  10. #10
    Membre régulier
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    133
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2012
    Messages : 133
    Points : 109
    Points
    109
    Par défaut
    J'ai réussi à faire ce que je souhaitais grâce à la solution de aDiguba.
    Cependant, toujours dans un soucis de factorisation, maintenant j'aimerais en plus de créer une classe, pouvoir utiliser les méthodes de cette classe.

    Je m'explique, cette portion de code, je la répète avec un nombre de classe certains. Ici c'est avec des tags, donc getListTag me renvoi une Lit<Tag>, cbTags, est un JComoboBox et getLibelle() est simplement un geter() qui nous retourne le libellé du tag à rajouter dans la comobobx.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for(Tag tag : contact.getListTag()){
                cbTags.addItem(tag.getLibelle());
            }
    Cependant, j'ai 4 classes, et au lieu d'avoir un getListTag j'ai un getListNomClasse, par exemple.

    Donc j'ai fais des recherches sur internet se rapprochant de la reflection, et je suis tombé sur la méthod, getMethod, et invoke, mais cela me renvoi un objet, et non pas une List<T> par exemple, est-ce possible ?

  11. #11
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Oublis la réflection pour cela !
    C'est assez casse-gueule et tu risques d'écrire 10 fois plus de code qu'il ne t'en faudrait pour dupliquer ton code actuel.


    A la rigueur tu pourrait hériter d'interface commune afin d'avoir la même méthode partout...


    a++

  12. #12
    Membre régulier
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    133
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2012
    Messages : 133
    Points : 109
    Points
    109
    Par défaut
    Ouais, c'est bien ce que je me disais, j'ai fais quelques tests et je me suis rendu compte que j'écrivais plus de lignes.

    J'vais tenter de les faire hériter d'une classe commune cela fonctionnera plus facilement.

    Merci pour ta réponse

  13. #13
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    d'accord avec adiguba. Le mieux à faire c'est ce genre de chose


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public interface Libellable {
      public String getLibelle();
    }
     
    public class Tag implement Libellable {
    }
     
     
    public void fillCombo(JComboBox box, List<? extends Libellable> items){
       for (Libellable item : items)
           box.addItem(item.getLibelle());
    }
     
    fillCombo(cbTags,contact.getListTag());
    Alternativement (ce que je préfère), ajoute directement les Tag dans tas Combobox et fournis à la combobox un renderer capable d'extraire le libellé. Au moins, tu aura plus facile à retrouver le Tag sélectionné.

  14. #14
    Membre régulier
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    133
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2012
    Messages : 133
    Points : 109
    Points
    109
    Par défaut
    Qu'entends tu par renderer ? Je comprend le fait de lui filer l'objet histoire de retrouver plus facilement ce que j'ai séléctionné mais qu'entends tu par lui filer un renderer ?

  15. #15
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    JCombobox.setRenderer(ListCellRenderer).

    un combobox, ça ne sait pas comment afficher un tag. Par défaut ça utilisera Tag.toString() ce qui en général ne donne pas bien. Un renderer permet de lui dire comment représenter visuellement ton objet Tag.

Discussions similaires

  1. factorisation de code
    Par calagan99 dans le forum ASP.NET
    Réponses: 7
    Dernier message: 21/05/2007, 09h00
  2. [C++] Factorisation de code
    Par xterminhate dans le forum C++
    Réponses: 6
    Dernier message: 07/11/2006, 16h21
  3. factoriser du code
    Par grabriel dans le forum Langage
    Réponses: 3
    Dernier message: 26/10/2006, 15h00
  4. Réponses: 7
    Dernier message: 01/08/2006, 11h58
  5. Réponses: 4
    Dernier message: 06/11/2003, 10h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo