Conception Cohésion Classe A - Gestion Authentification Utilisateur
Exercice 1 - Analyse et conception de la classe Java Question 1 - But de la classe A Le but de la classe A (et de sa méthode manageUser ) est de permettre à un utilisateur de récupérer ses informations personnelles (nom et prénom) depuis une base de données, en s'authentifiant à l'aide d'un identifiant ( login ) et d'un mot de passe ( password ).
D'après le document Conception Cohésion Classe A - Gestion Authentification Utilisateur
Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Document source
Génie Logiciel, Programming · Université de la Manouba · PDF · 6 pages · 2012
Afficher l'aperçu du document
Exercice 1 - Analyse et conception de la classe Java
Question 1 - But de la classe A
Le but de la classe A (et de sa méthode manageUser) est de permettre à un utilisateur de récupérer ses informations personnelles (nom et prénom) depuis une base de données, en s'authentifiant à l'aide d'un identifiant (login) et d'un mot de passe (password).
Concrètement, le code effectue trois étapes consécutives :
- Il valide le format du login et du mot de passe.
- Il récupère les informations de l'utilisateur dans la base de données.
- Il formate ces informations pour retourner un message d'accueil convivial (user-friendly) ou un message d'erreur à l'utilisateur.
Question 2 - Évaluation de la cohésion
La qualité de ce code en matière de cohésion est mauvaise : la classe A n'est pas cohésive.
Explication :
La cohésion mesure le degré de spécialisation d'une classe. Une classe fortement cohésive ne doit avoir qu'une seule et unique responsabilité (Single Responsibility Principle). Dans le cas présent, la classe A est monolithique et effectue à elle seule des opérations qui appartiennent à des couches logiques distinctes et qui n'ont pas de lien direct entre elles :
- La validation des règles de saisie utilisateur.
- La connexion et l'interrogation de la base de données (accès aux données).
- La logique de présentation et le formatage du message de l'interface graphique (GUI).
Question 3 - Amélioration de la cohésion
Pour rendre le système fortement cohésif, il faut décomposer la classe A en plusieurs classes ayant chacune un rôle unique et bien défini. Bien qu'un diagramme graphique ne puisse être dessiné ici, voici la description structurelle (l'équivalent du diagramme de classes) de cette amélioration, suivie de l'implémentation corrigée.
Structure du nouveau diagramme de classes :
UserManager: Classe principale (Contrôleur) qui délègue les tâches aux classes spécialisées.UserCredentialChecker: Spécialisée uniquement dans la validation des identifiants de l'utilisateur.UserDao(Data Access Object) : Spécialisée uniquement dans l'accès à la base de données pour récupérer l'entitéUser.GuiMessageFormater: Spécialisée uniquement dans le formatage de la chaîne de caractères à afficher à l'utilisateur.
Voici le code implémentant cette architecture déléguée (les classes utilitaires StringUtils et le modèle User sont assumés existants dans le paquet).
Le contrôleur : UserManager
package fr.netapsys.training;
import java.sql.SQLException;
public class UserManager {
private static UserManager instance;
private UserManager() {
}
public void manageUser(final String login, final String password)
throws ClassNotFoundException, SQLException {
// Étape 1 : Validation des paramètres
if (UserCredentialChecker.getInstance().check(login, password)) {
// Étape 2 : Récupération depuis la base de données
final User user = UserDao.getInstance().retrieve(login, password);
// Étape 3 : Formatage du message pour l'interface
GuiMessageFormater.getInstance().formatUIMessage(user);
}
}
public static UserManager getInstance(){
if (instance == null) {
instance = new UserManager();
}
return instance;
}
}
Le validateur : UserCredentialChecker
package fr.netapsys.training;
public class UserCredentialChecker {
private static UserCredentialChecker instance;
public boolean check(final String login, final String password) {
final boolean isAuthenticate = !StringUtils.isEmpty(login)
&& !StringUtils.isEmpty(password) && (login.length() > 3);
return isAuthenticate;
}
public static UserCredentialChecker getInstance(){
if (instance == null) {
instance = new UserCredentialChecker();
}
return instance;
}
}
L'accès aux données : UserDao
package fr.netapsys.training;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class UserDao {
private static UserDao instance;
public User retrieve(final String login, final String password)
throws ClassNotFoundException, SQLException{
final User user = new User();
Class.forName("org.postgresql.Driver");
final String url = "jdbc:postgresql://localhost:5433/CBDB";
final String dbUser = "cashbird";
final String dbPassword = "cashbird";
final Connection connection = DriverManager.getConnection(url, dbUser, dbPassword);
final Statement statement = connection.createStatement();
final ResultSet resultSet = statement.executeQuery(
"SELECT * FROM utilisateur WHERE login='" +
login + "' AND password = '" + password+"'");
while(resultSet.next()){
user.setFirstname(resultSet.getString("FIRSTNAME"));
user.setLastname(resultSet.getString("LASTNAME"));
user.setAuthenticate(true);
}
statement.close();
connection.close();
return user;
}
public static UserDao getInstance(){
if (instance == null) {
instance = new UserDao();
}
return instance;
}
}
Le formateur : GuiMessageFormater
package fr.netapsys.training;
public class GuiMessageFormater {
private static GuiMessageFormater instance;
public String formatUIMessage(final User user){
final StringBuilder uiMessage = new StringBuilder();
if (user.isAuthenticate()) {
uiMessage.append("M. " + user.getFirstname() +
" " + user.getLastname() + ", bienvenue chez NETAPSYS !");
} else {
uiMessage.append("login ou mot de passe incorrect !");
}
return uiMessage.toString();
}
public static GuiMessageFormater getInstance(){
if (instance == null) {
instance = new GuiMessageFormater();
}
return instance;
}
}
Note sur l'extensibilité : Cette nouvelle architecture permet d'ajouter de nouveaux comportements sans modifier les classes existantes ni surcharger le contrôleur, par exemple en ajoutant une étape UserAdditionnalTreator.getInstance().treat(user); à la fin de la méthode manageUser.
Exercice 2 - Analyse de couplage et métrique LCOM (C++)
Note : Le code source C++ de cet exercice n'étant pas reproduit dans le document d'origine, la résolution suivante s'appuie sur l'analyse conceptuelle des relations décrites dans la solution.
Question 1 - Couplage entre les classes
Dans un diagramme de classes décrivant ces relations, les flèches d'utilisation partent des classes clientes vers les classes fournisseuses de services. Voici l'analyse des couplages existants :
Entre la classe Rectangle et la classe Point :
- Relation 1 :
RectangleutilisePointvia l'appel d'une méthode (par exempleA.getx()).- Type de couplage : Couplage de données. La classe cliente récupère une donnée simple (ici un
floatreprésentant la coordonnéex).
- Type de couplage : Couplage de données. La classe cliente récupère une donnée simple (ici un
- Relation 2 :
RectangleutilisePointlors de la création d'un objetPointpar son constructeur, en lui passant des données.- Type de couplage : Couplage de données. La classe
Rectanglecrée une instance pour accéder aux fonctionnalités de la classePoint, échangeant ainsi des données primitives.
- Type de couplage : Couplage de données. La classe
Entre la classe ListeRectangles et la classe NoeudListe :
- Relation 1 :
ListeRectanglesutiliseNoeudListelors de la création d'un objet via le constructeur en y passant des données.- Type de couplage : Couplage de données.
- Relation 2 :
ListeRectanglesutiliseNoeudListeen appelant la méthodesetSuivant(). Cette méthode prend en paramètre une structure de données entière (une variabletetede typeNoeudListe).- Type de couplage : Couplage de structure de données (souvent appelé "stamp coupling"). Les classes échangent un type composite plutôt que des types primitifs simples.
Question 2 - Calcul de la métrique de manque de cohésion (LCOM)
La métrique LCOM (Lack of Cohesion of Methods) évalue le degré de partage d'attributs entre les méthodes d'une même classe. Calculons le LCOM pour la classe Point.
1. Identification des ensembles d'attributs utilisés par chaque méthode :
- I1 = Attributs utilisés par le constructeur
Point()= {x, y} - I2 = Attributs utilisés par la méthode
getx()= {x} - I3 = Attributs utilisés par la méthode
gety()= {y}
2. Analyse des paires de méthodes : Nous devons comparer toutes les paires possibles de méthodes ((I1, I2), (I1, I3), et (I2, I3)) pour vérifier si elles partagent au moins un attribut (intersection non vide) ou non (intersection vide).
- Intersection entre I2 et I3 : {x} ∩ {y} = ∅ (Vide). La paire (I2, I3) ne partage aucun attribut. Elle appartient à l'ensemble P.
- Intersection entre I1 et I2 : {x, y} ∩ {x} = {x} (Non vide).
La paire (I1, I2) partage l'attribut
x. Elle appartient à l'ensemble Q. - Intersection entre I1 et I3 : {x, y} ∩ {y} = {y} (Non vide).
La paire (I1, I3) partage l'attribut
y. Elle appartient à l'ensemble Q.
3. Calcul des cardinaux :
- |P| (nombre de paires sans attribut commun) = 1
- |Q| (nombre de paires avec attributs communs) = 2
4. Application de la formule LCOM : LCOM(Point) = Max(|P| - |Q|, 0) LCOM(Point) = Max(1 - 2, 0) LCOM(Point) = Max(-1, 0) LCOM(Point) = 0
Conclusion : Un LCOM de 0 indique une absence de manque de cohésion. La classe Point possède donc une forte cohésion, ce qui est le résultat attendu pour une classe conceptuellement pure.
Méthode
Pour réussir ce type d'épreuve en Génie Logiciel, voici les points fondamentaux à maîtriser :
- Reconnaître le "Code Smell" : Face à un code existant, identifiez systématiquement les blocs logiques. Si une classe contient des termes liés aux bases de données (
ResultSet,Connection), au métier (isParametersValid), et à l'interface (StringBuilder,uiMessage), elle viole le principe de responsabilité unique. C'est votre signal pour la décomposer. - Appliquer les bons patrons de conception (Design Patterns) : La solution de l'exercice 1 utilise de façon répétée le patron Singleton (via
getInstance()) pour les classes de service et l'approche DAO (Data Access Object) pour isoler les requêtes SQL. Ce sont des standards de l'industrie que vous devez savoir intégrer lors d'une refonte (refactoring). - Comprendre les types de couplage : Mémorisez l'échelle de couplage. Le passage de données primitives (int, float) est le couplage le plus faible et le plus désirable (Couplage de données). Le passage d'objets ou de structures entières (Couplage de structure de données / Stamp coupling) lie davantage les classes entre elles.
- Maîtriser le calcul du LCOM : Le LCOM n'est qu'une soustraction entre deux comptages. Posez calmement vos ensembles d'attributs pour chaque méthode, testez toutes les intersections possibles (n × (n-1) / 2 paires au total), puis comptez. Souvenez-vous que le LCOM ne peut pas être négatif : la fonction
Max(..., 0)protège le résultat final. Un LCOM de 0 est le meilleur score possible (cohésion maximale).
Commentaires
Aucun commentaire pour le moment. Posez la première question.