UNIVERSITE DE LA MANOUBA
Matière : Génie Logiciel 1
-----¤¤¤¤-----
Classes : I.I. 2
ECOLE NATIONALE DES SCIENCES DE L'INFORMATIQUE
A-U : 2012-2013
TD : Principes de Conception
Exercice 1
Pour le programme Java ci-dessous :
1. Enoncer textuellement le but de la classe A.
2. Evaluer la qualité de ce code en terme de cohésion. Expliquer.
3. Proposer une amélioration au niveau cohésion. Décrire cette amélioration par un diagramme
de classes sans implémenter le code interne.
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 A {
public String manageUser(final String login, final String password)
throws ClassNotFoundException, SQLException {
String uiMessage = "";
final User user = new User();
// first check user parameters
final boolean isParametersValid = !StringUtils.isEmpty(login) && !StringUtils.isEmpty(password)
&& ( login.length() > 3 ) ;
// then retrieve everything from database
if (isParametersValid) {
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();
Publicité
// finally format GUI message
if (user.isAuthenticate()) {
uiMessage = "M. " + user.getFirstname() + " " + user.getLastname() + ", bienvenue chez NETAPSYS !";
}else {
uiMessage = "login ou mot de passe incorrect !";
}
return uiMessage;
}else {
uiMessage = "Vous devez renseignez tous les champs !";
}
return uiMessage;
}}
1
Correction exercice 1 :
Que fait ce code? Il permet à un utilisateur de récupérer ses informations (nom, prénom) d'une base
de données, à partir de son login et mot de passe. On commence par valider le login et le mot de
passe, ensuite on récupère les informations de la base de données, et enfin on les formate pour
retourner à notre utilisateur un message user-friendly.
Cette classe A n'est pas cohésive : elle effectue à elle seule des opérations qui n'ont pas de lien
direct entre elles : validation, récupération de la base, formatage.
On peut rendre une classe fortement cohésive en la découpant en plusieurs classes qui ont un rôle
bien spécifique. Voici ce que donne la classe UserManager (la classe A) après ce petit coup de
décomposition.
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 {
// first check user parameters
if (UserCredentialChecker.getInstance().check(login, password)) {
// then retrieve everything from database
final User user = UserDao.getInstance().retrieve(login, password);
// finally format GUI message
GuiMessageFormater.getInstance().formatUIMessage(user);
}
}
public static UserManager getInstance(){
if (instance == null) {
instance = new UserManager();
}
return instance;
Publicité
}
}
Voici à quoi ressemble la classe 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) {
2
instance = new UserCredentialChecker();
}
return instance;
}
}
Et la classe 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"));
Publicité
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;
}
}
Et enfin, la classe GuiMessageFormater.
package fr.netapsys.training;
public class GuiMessageFormater {
private static GuiMessageFormater instance;
public String formatUIMessage(final User user){
3
final StringBuilder uiMessage = new StringBuilder();
if (user.isAuthenticate()) {
uiMessage.append("Mr " + 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;
}
}
La classe UserManager délègue désormais les 3 traitements à des classes spécialisées :
• UserCredentialChecker pour la validation des paramètres de l'utilisateur
• UserDao pour la récupération de données de la base
• GuiMessageFormater pour le formatage des données
Un des inconvénients de l'architecture n°1 est qu'elle n'est pas extensible. Si à l'avenir on doit
rajouter d'autres traitements de gestion d'utilisateur, notre classe va très vite déborder et devenir
complètement illisible. Par contre, dans la 2e architecture, il suffira tout simplement de déléguer le
traitement à la nouvelle classe spécialisée et le tour est joué.
Publicité
public void manageUser(final String login, final String password)
throws ClassNotFoundException, SQLException {
// first check user parameters
if (UserCredentialChecker.getInstance().check(login, password)) {
// then retrieve everything from database
final User user = UserDao.getInstance().retrieve(login, password);
// finally format GUI message
GuiMessageFormater.getInstance().formatUIMessage(user);
// rajout d'une nouvelle fonctionnalité
UserAdditionnalTreator.getInstance().treat(user);
}
}
4
Exercice 2
Pour le programme C++ ci-dessous :
1. Présenter le couplage entre classes par un diagramme de classes complété par des flèches
indiquant pour chaque fonction celles qu’elles appellent en dehors de leur classe. Préciser le
type du couplage.
2. Calculer la métrique de manque de cohésion des méthodes (LCOM).
5
Correction exercice 2
1. Type de couplage
Classe Rectange et Classe Point
- Rectangle utilise Point (i.e A.getx()) : cette relation d’utilisation représente un couplage de
données (i.e : x est un float)
- Rectangle utilise Point : pour la création d’un objet de type point (par le constructeur) la
classe Rectangle passe des données à la classe Point. Cette relation d’utilisation représente
un couplage de données. La classe Rectangle a besoin de services fournis par la classe
Point. Elle crée un objet de type Point pour accéder aux fonctionnalités de cette classe.
Classe ListeRectangles et NoeudListe
- ListeRectangles utilise NoeudListe : pour la création d’un objet de type NoeudListe (par le
constructeur) la classe ListeRectangles passe des données à la classe NoeudListe. Cette
relation d’utilisation représente un couplage de données.
- ListeRectangles utilise NoeudListe : la méthode setSuivant () de NoeudListe prend comme
paramètre une structure de données ‘tete’ de type NoeudListe. Cette relation d’utilisation
représente un couplage de structure de données.
2. LCOM
La classe Point : forte cohésion car
I1=I(Point()) = {x, y}, I2=I (getx()) = {x},I3= I (gety()) = {y}
P={(I2, I3)} (cid:1)|P|= 1
Q={(I1, I2), (I1, I3)} (cid:1)|Q|= 2
LCOM(Point) = Max (1-2, 0) = 0
6