class Distributeur{
private:
CreditCard *m_userCard;
public:
Distributeur(const CreditCard &userCard){
m_userCard = new CreditCard;
m_userCard->m_Name = userCard.m_Name;
//on a recu "userCard" en entree et on ne l'a pas utilisee
}
void retirerCarte(){
// pouf ! on vient de retirer la carte sans la libérer
m_userCard = nullptr;
}
void insererCarte(const CreditCard &userCard){
// pouf ! on remplace la carte sans libérer celle potentiellement présente
m_userCard = new CreditCard;
m_userCard->m_Name = userCard.m_Name;
//on a recu "userCard" en entree et on ne l'a pas utilisee
}
};
Comment je peux modifier ça pour libérer la carte? Je vois pas trop se que je peux faire à ce niveau à part ne pas utiliser de pointeur (Par curiosité, de toute façon je n'utilise plus les pointeurs pour refaire mon code la)
Pourquoi Koala dans ton exemple de code, tu mets une fonction private qui retourne le code de la carte de crédit alors que dans tous les cas la classe distributeur a accés aux elements privés de credit card par amitié?
En gros c'est quoi l'interet d'écrire
c.getCode(); // Toi tu as juste écris c.code() dans la classe distributeur
plutôt que
c.secretpass;
Si j'ai bien compris, c'est en fonction de se que l'utilisateur du distributeur à accés ou non? Ca reste un peu flou à mon sens cette partie de code..
Autant supprimer la fonction, et utiliser directement l'attribut étant donné qu'ils sont amis
La qualité cardinale d'une bonne conception est de rendre simple l'implémentation de la solution logicielle.
Une chose qui tend à rendre l'usage de composant logiciel simple, c'est de les rendre indépendant les uns des autres.
La modularisation et l'encapsulation permettent de renforcer facilement l'indépendance.
En passant par un accesseur, comme getCode, c'est un moyen primitif de rendre Distributeur et CreditCard un peu plus indépendant.
Pour avoir travaillé il y a plusieurs décennies dans la carte bancaire, je n'airais pas modéliser la chose de cette manière.
Le code n'est pas communiqué entre la carte et le distributeur mais juste des résultats de hash d'un challenge-response.
La carte génère une valeur aléatoire, la communique au distributeur, le distributeur utilise le code entré par l'utilisateur pour hashé la valeur aléatoire, et envoie le résultat à la carte qui elle dit OK ou non (elle aussi fait le hash).
Si tu modélises cela, tu vois que l'accès directement aux membres d'une classe n'est que très rarement une bonne solution car elle empêche l'évolution de l'implémentation de la classe "accédée" sans avoir à toucher à toutes les classes "accédantes". Friend permet de réduire le nombre de classe mais elles sont toujours impactées, donc boule de neige de modifications toujours possible.
Avec l'utilisation d'un accesseur, il serait possible de "calculer" le code sans avoir à changer le code utilisateur de la classe.
Mais bon, avec une interface plus proche de la réalité, la question ne se pose même pas.
- Edité par bacelar 15 septembre 2017 à 17:26:23
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Il est vrai que, à y réfléchir plus correctement, on pourrait dire que la vérification d'un code secret et la possibilité de modifier le code secret de la carte sont autant de services que l'on est en droit d'attendre de la part de la carte de crédit.
Nous pourrions donc supprimer l'amitié entre le distributeur et la carte de crédit et transformer la carte de crédit pour lui donner une forme proche de
class CreditCard{
public:
CreditCard(std::string const & name,
std::string const & surname,
date expiration, unsigned int code)
:name_{name}, surname_{surname},
expiration_{expiration}, code_{code},
tries_{0}{}
date const & expiration() const{return expiration_;}
std::string const & userName() const{return name_;}
std::string const & userSurName() const{return name_;}
bool blocked() {return tries_=3;}
bool checkCode(unsigned int code) const{
if(code == code){
codeAccepted();
return true;
}
codeRejected();
return false;
}
bool changeCode(unsigned int currentCode,
unsigned int newCode){
bool check = checkCode(code);
if(! check)
return false;
code_==newCode;
return true;
}
private:
void codeAccepted(){tries_=0;}
void codeRejected(){++ tries_;}
std::string name_;
std::string surname_;
date expiration_;
unsigned int code_;
unsigned int tries_;
};
@bacelar : je présumes que, sous cette forme, c'est déjà beaucoup plus proche (à l'exception du type utilisé pour représenter le code, et de toute sa gestion interne) de l'interface que tu utilisais ?
@Artanno62 : le but de l'encapsulation n'est pas de cacher les données pour le plaisir de le faire, mais bien de faire en sorte que l'utilisateur d'une donnée ne puisse pas faire de connerie en la manipulant.
Il est vrai que, lorsqu'on empêche l'utilisateur d'accéder directement à une donnée, on a d'autant plus facile d'éviter qu'il ne fasse une connerie en la manipulant. Mais cela ne résout malgré tout qu'une partie du problème, car une donnée n'a réellement de sens que s'il est possible de la manipuler: une donnée que tu ne peut manipuler d'aucune manière est une donnée qui ne sert à rien et qui est donc inutile dans ton programme.
En réalité, ce qu'il faut surtout faire, c'est poser "des jalons" qui permettent à l'utilisateur de savoir "ce qu'il peut faire" avec la donnée en question en lui fournissant une liste de fonctions qu'il peut appeler dans le cadre de l'utilisation de la donnée.
Bien sur, nous veillerons à ce que les fonctions que nous mettons à disposition de l'utilisateur soient vérifiables, vérifiées et qu'elles fassent le boulon qu'on attend de leur part.
A partir du moment où l'on fournit à l'utilisateur les fonctions qui permettent de manipuler une donnée de manière sécurisante, on s'en fout pas mal que la donnée en question soit accessible ou non:
Soit il utilisera la donnée de la manière que nous aurons préconisée, et il ne devrait avoir aucun problème, soit "il fait le con" en allant chipoter à des choses auxquelles il n'aurait jamais du toucher. Mais, dans ce cas, il ne pourra s'en prendre qu'à lui-même
Alors, bien sur, si on fournit à l'utilisateur un ensemble de fonctions qui lui permettent de manipuler des données auxquelles il n'a pas d'accès "direct", c'est encore mieux, car ça lui évitera sans doute la tentation de "faire le con" en allant chipoter à ce qu'il ne doit pas.
Mais s'il y a une chose à retenir au final, c'est que toutes les manipulations que tu peux envisager sur une donnée quelconque doivent être "garantie sans danger", et que le seul moyen de fournir cette garantie est de ... fournir une fonction qui effectuera la manipulation et les vérifications nécessaires.
C'est dans cette optique que j'avais fourni des fonctions privée checkCode et changeCode : pour garantir que, si "quelque chose" passait par ces fonctions, le résultat serait correct, vérifiable et reproductible. Chose que je n'aurais jamais pu garantir si j'avais laissé la classe Distributeur accéder "à sa guise" à la donnée membre "code_"
Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
Une carte bancaire est une forteresse, il est hors de question de laisser quiconque lui demander quel est ton code. Le principe est plutôt:
La carte pose une question, le distributeur demande le code à l'utilisateur, se sert du code pour composer une réponse à la carte. En fonction de la réponse, la carte répond oui ou non. Si le distributeur pouvait demander son code à la carte, il serait trop facile de faire de faux distributeurs. Faire de fausse cartes est nettement plus compliqué et les distributeurs ont eux aussi des challenges pour détecter les fausses cartes. On ne peut pas vraiment dire que la confiance règne
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C