Voir le flux RSS

autran

[Actualité] Migration d'objets metier de Java vers JavaScript

Note : 4 votes pour une moyenne de 5,00.
par , 21/03/2016 à 00h53 (1913 Affichages)
Lors de précédents billets, j'ai évoqué la migration d'application JEE vers des architectures JavaScript. Les migrations que j'ai expérimentées m'ont permis de porter des applications JEE vers AngularJS pour le front office et Node.js pour le back-office. Comme dans les blogs précédents, je rappelle que ces migrations sont envisageables pour des applications légères.
Dans ce billet, j'aborderai la migration des objets métier. En JEE ces objets métier sont des POJO (Plain Old Java Objects) c'est-à-dire des classes. Aussi ces objets pourront devenir en JavaScript des POJO (Plain Old Javascript Objects) c'est-à-dire encore des classes.
Pour être autorisé à parler de classes en JavaScript, il faut bien entendu implémenter le standard ES6.
Regardons de plus près comment on pourrait migrer un objet Owner qui agrégerait des objets cellules.
Voici une implémentation en Java :
Code java : 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
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class Cellule {
 
	// attributs
	private String name = "";
	private Owner owner = null;
 
	// constructeur
	public Cellule(String name){
		this.setName(name);
	}
 
	// méthodes --> setter et getter
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public Owner getOwner() {
		return owner;
	}
 
	public void setOwner(Owner owner) {
		this.owner = owner;
	}
}
 
public class Owner 
{
	// attributs
	private ArrayList<Cellule> cellules;
 
	// constructeur
	public Owner(){
		this.cellules = new ArrayList<Cellule>();
	}
 
	// méthodes
	public int getSize(){
		return this.cellules.size();
	}
 
	public int addElement(Cellule e){
		if(e.getOwner() != this) 
			e.setOwner(this);
		this.cellules.add(e);
		return this.cellules.indexOf(e);
	}
 
	public Cellule getElementAtIndex(int index){
		return this.cellules.get(index);
	}
}

Et maintenant l’implémentation en JavaScript :
Code javascript : 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
22
23
24
25
26
27
28
29
class Cellule { 
    constructor(name){ 
		// attributs
		this.name = name;
		this.owner = null;
    } 
}
 
class Owner{
	constructor(){ 
		// attributs
		this.cellules = [];
    }
 
	// methodes
	getSize(){
		return this.cellules.length;
	}
 
	addElement(cellule){
		if(cellule.owner != this) 
			cellule.owner = this;
		return this.cellules.push(cellule);
	}
 
	getElementAtIndex(index){
		return this.cellules[index];
	}
}

On remarque que les règles de passage de Java à JavaScript semblent assez simples si on accepte quelques petites entorses aux règles strictes de l'objet et notamment l'encapsulation grâce aux mentions de protection. En effet, en Java les propriétés sont privateset donc seulement accessibles au travers de getter et setter. Tandis qu'en JavaScript, tout est public, mais cela permet de faire l'économie d'écriture des getter et setter.
Cependant, si l'on n'implémente pas l'héritage dans l'organisation des objets métier, on peut sans problème s'abstraire de ces mentions de protection. Et on remarque que l'on n'utilise que rarement l'héritage dans les tiers métier.

Donc, il semble que la migration des objets métier de Java à JavaScript soit assez simple.

Envoyer le billet « Migration d'objets metier de Java vers JavaScript » dans le blog Viadeo Envoyer le billet « Migration d'objets metier de Java vers JavaScript » dans le blog Twitter Envoyer le billet « Migration d'objets metier de Java vers JavaScript » dans le blog Google Envoyer le billet « Migration d'objets metier de Java vers JavaScript » dans le blog Facebook Envoyer le billet « Migration d'objets metier de Java vers JavaScript » dans le blog Digg Envoyer le billet « Migration d'objets metier de Java vers JavaScript » dans le blog Delicious Envoyer le billet « Migration d'objets metier de Java vers JavaScript » dans le blog MySpace Envoyer le billet « Migration d'objets metier de Java vers JavaScript » dans le blog Yahoo

Mis à jour 22/03/2016 à 10h58 par ClaudeLELOUP

Catégories
Java , Javascript , Développement Web

Commentaires

  1. Avatar de danielhagnoul
    • |
    • permalink
    Accesseur et mutateur (get/set) existent depuis ES5 et sont utilisables dans une classe ES2015. Il est tout à fait possible d'avoir des propriétés "privées" (inaccessible à l'extérieur de la classe) et "protégées" (accessible par get/set). Comme le module ES2015 n'est toujours pas disponible en natif, il faut recourir à une clôture (closure) pour protéger les propriétés et méthodes privées.

    Voici un exemple fonctionnel en ES2015 natif (Chrome 49+ ou Firefox 46+) sur un sujet que tu connais bien. Il contient les classes Panier, LignePanier et Article. Attention ce n'est pas "utilisable en l'état", c'est juste l'ébauche d'une solution, mais c'est suffisant pour illustrer le propos.

    Références


    Code html : 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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    <!DOCTYPE html>
    <html lang="fr" dir="ltr">
    <head>
      <meta http-equiv="cache-control" content="public, max-age=60">
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <meta name="author" content="Daniel Hagnoul">
      <title>Test</title>
      <style>
     
     
      </style>
      <script>
        'use strict';
        
        document.addEventListener( 'DOMContentLoaded', function( ev ){
          
          const
            kGetType = function( Obj ){
              return Object.prototype.toString.call( Obj ).match( /\s([a-zA-Z]+)/ )[ 1 ].toLowerCase();
            },
            Article = ( function(){
              const
                kCode = Symbol( 'Code' ),
                kCodeType = 'number',
                kSetCode = function( obj, value ){
                  if ( kGetType( value ) === kCodeType ){
                    obj[ kCode ] = value;
                  } else {
                    throw `Type des paramètres incompatibles.
                            code : ${ kCodeType } attendu`;
                  }
                  return obj;
                },
                kNom = Symbol( 'Nom' ),
                kNomType = 'string',
                kSetNom = function( obj, value ){
                  if ( kGetType( value ) === kNomType ){
                    obj[ kNom ] = value;
                  } else {
                    throw `Type des paramètres incompatibles.
                            nom : ${ kNomType } attendu`;
                  }
                  return obj;
                },
                kPrix = Symbol( 'Prix' ),
                kPrixType = 'number',
                kSetPrix = function( obj, value ){
                    if ( kGetType( value ) === kPrixType ){
                      obj[ kPrix ] = value;
                    } else {
                      throw `Type des paramètres incompatibles.
                              prix : ${ kPrixType } attendu`;
                    }
                    return obj;
                };
                
              return class cArticle {
                constructor( code, nom, prix ){
                  kSetCode( this, code );
                  kSetNom( this, nom );
                  kSetPrix( this, prix );
                }
                get code(){
                  return this[ kCode ];
                }
                get nom(){
                  return this[ kNom ];
                }
                get prix(){
                  return this[ kPrix ];
                }
                set prix( value ){
                  kSetPrix( this, value );
                }
              }
            })(),
            LignePanier = ( function(){
              const
                kArticle = new WeakMap(),
                kArticleType = 'object',
                kSetArticle = function( obj, value ){
                  if ( kGetType( value ) === kArticleType ){
                    kArticle.set( obj, value );
                  } else {
                    throw `Type des paramètres incompatibles.
                            article : ${ kArticleType } attendu`;
                  }
                  return obj;
                },
                kNombre = Symbol( 'Nombre' ),
                kNombreType = 'number',
                kSetNombre = function( obj, value ){
                  if ( kGetType( value ) === kNombreType ){
                    obj[ kNombre ] = value;
                    kSetPrix( obj );
                  } else {
                    throw `Type des paramètres incompatibles.
                            nom : ${ kNombreType } attendu`;
                  }
                  return obj;
                },
                kPrix = Symbol( 'Prix' ),
                kPrixType = 'number',
                kSetPrix = function( obj ){
                  let value = kArticle.get( obj ).prix * obj[ kNombre ];
                  
                  if ( kGetType( value ) === kPrixType ){
                    obj[ kPrix ] = value;
                  } else {
                    throw `Type des paramètres incompatibles.
                            prix : ${ kPrixType } attendu`;
                  }
                  return obj;
                };
                
              return class cLignePanier {
                constructor( article, nombre ){
                  kSetArticle( this, article );
                  kSetNombre( this, nombre );
                }
                get nombre(){
                  return this[ kNombre ];
                }
                set nombre( value ){
                  kSetNombre( this, value );
                }
                get prix(){
                  return this[ kPrix ];
                }
              }
            })(),
            Panier = ( function(){
              const
                kLignes = new WeakMap(),
                kLignesType = 'object',
                kSetLignes = function( obj, value ){
                  if ( kGetType( value ) === kLignesType ){
                    kLignes.get( obj ).push( value );
                    kSetPrix( obj );
                  } else {
                    throw `Type des paramètres incompatibles.
                            lignes : ${ kLignesType } attendu`;
                  }
                  return obj;
                },
                kSpliceLignes = function( obj, value ){
                  if ( kGetType( value ) === kLignesType ){
                    let index = kLignes.get( obj ).findIndex( function( item, i ){
                      if ( item === value ) {
                        return true;
                      }
                    });
                    
                    kLignes.get( obj ).splice( index, 1 );
                    kSetPrix( obj );
                  } else {
                    throw `Type des paramètres incompatibles.
                            lignes : ${ kLignesType } attendu`;
                  }
                  return obj;
                },
                kPrix = Symbol( 'Prix' ),
                kPrixType = 'number',
                kSetPrix = function( obj ){
                  let value = kLignes.get( obj ).reduce( function( value, item, i ){
                    return value + item.prix;
                  }, 0 );
                  
                  if ( kGetType( value ) === kPrixType ){
                    obj[ kPrix ] = value;
                  } else {
                    throw `Type des paramètres incompatibles.
                            prix : ${ kPrixType } attendu`;
                  }
                  return obj;
                };
                
              return class cPanier {
                constructor( ligne ){
                  kLignes.set( this, [] );
                  kSetLignes( this, ligne );
                }
                get prix(){
                  return this[ kPrix ];
                }
                addLigne( ligne ){
                  kSetLignes( this, ligne );
                }
                removeLigne( ligne ){
                  kSpliceLignes( this, ligne );
                }
              }
            })();
            
          let
            articleMontreRolex = new Article( 235689, 'Montre Rolex', 2357 ),
            articleFerrariE = new Article( 784512, 'Ferrari E', 896234 ),
            articlePainLuxe = new Article( 134679, 'Pain de luxe', 17 ),
            ligneRolex = new LignePanier( articleMontreRolex, 2 ),
            ligneFerrari = new LignePanier( articleFerrariE, 1 ),
            lignePain = new LignePanier( articlePainLuxe, 3 ),
            panierDVJH = new Panier( ligneRolex );
          
          console.log( articleMontreRolex );
          console.log( articleFerrariE );
          console.log( articlePainLuxe );
          
          console.log( ligneRolex );
          console.log( ligneFerrari );
          console.log( lignePain );
          
          panierDVJH.addLigne( ligneFerrari );
          panierDVJH.addLigne( lignePain );
          
          panierDVJH.removeLigne( ligneFerrari );
          
          console.log( panierDVJH );
            
        });
      </script>
    </head>
    <body>
     
     
    </body>
    </html>
  2. Avatar de autran
    • |
    • permalink
    Excellent Daniel

    Mais du coup le mapping Java <--> JavaScript est beaucoup moins net.
    Or dans mon projet, je dois prendre des racourcis pédagigiques pour raccrocher les Javaistes au JS.

    Ta connaissance académique du langage nous serait bien utile sur le projet de tuto que l'on mène actuellement. Alors si tu veux faire partie de la team, n’hésite pas.
  3. Avatar de renaudpawlak
    • |
    • permalink
    Hello,

    Pour info, JSweet (http://www.jsweet.org) permet d'automatiser ce genre de transformations.

    Actuellement il ne supporte pas les collections Java (il faut utiliser des tableaux), mais c'est en cours de développement...

    /Renaud
  4. Avatar de Invité
    • |
    • permalink
    Bonjour, code en Anglais, je ne regarde pas.:zoubi: En Francophonie, on utilise des noms de variables Françaises. Je ne suis pas Anglais.
  5. Avatar de autran
    • |
    • permalink
    Tu penses qu'aimer le français implique de détester l'anglais.
    Nous ne sommes pas dans une logique d'opposition.

    Bien au contraire, dans le monde du développement, nommer des variables en utilisant la langue internationale permet d'ouvrir ton code au monde.
    Sinon on pensera que tu ne souhaites réserver ton code qu'à ceux que tu en estimes digne, c'est à dire les français

    D'ailleurs, je ne pense pas une seule seconde que les SSII françaises de l'open source puissent pousser leurs développeurs vers une francisation de leur code source.
  6. Avatar de Mouke
    • |
    • permalink
    Citation Envoyé par devwebsympa
    Bonjour, code en Anglais, je ne regarde pas. En Francophonie, on utilise des noms de variables Françaises. Je ne suis pas Anglais.
    Logique ridicule, réductrice et néfaste.