Bonjour les agrumes !
La bêta a été mise à jour et décante sa pulpe
à l’adresse suivante :
Merci d’avance pour vos commentaires.
Après le retour de validation de @adri1, la partie sur la POO est remaniée, dans la partie POO chantier qui sera à terme la partie POO. En voici un plan.
Objets et classes
Ruby et les objets
- C’est quoi un objet ?
- Ruby est un langage orienté objet, tout est objet en Ruby.
- On agit sur les objets à l’aide de méthodes.
- Création du premier objet avec
Objct.new
et ajout de méthodes à cet objet.
- Introduction des attributs et de méthodes pour y accéder et les modifier.
Un modèle de construction
- Classe = moule pour créer des objets.
- Création de la première classe.
- Vocabulaire instances, méthodes d’instance, etc.
- Constructeur avec méthode
initialize
.
Des méthodes usuelles
- Accesseurs et mutateurs avec
attr_reader
, attr_writer
et attr_accessor
.
- Tout ce qui est conversion (
to_s
, etc.).
- Opérateurs sont aussi des méthodes.
Exercices
Création d’une classe pour représenter des durées.
Les classes plus en profondeur
Retour sur les méthodes
- Les méthodes d’instances sont dans les classes, pas dans les objets.
- On peut ouvrir une classe.
- Méthodes singletons sont aussi dans une classe appelée classe singleton.
- Algorithme de lookup => regarder les méthodes d’instances dans la classe singleton, puis celles dans la classe, puis celles dans
Object
.
Objet courant
- Quand on écrit
method_name
, Ruby sait pour quel objet il faut appeler cette méthode => objet courant.
- Plot twist :
puts
, print
et les méthodes déclarées au top level sont des méthodes de tous les objets ce qui explique qu’on puisse les appeler partout.
self
permet d’accéder à l’objet courant.
- Méthodes bang.
main
= objet courant au top level.
Les classes sont… des objets
- Classes ont des méthodes.
- Définir méthodes de classe = définir méthodes singleton pour un objet qui est la classe en question.
- Utile par exemple pour fournir d’autres constructeurs.
- En tant qu’objet, a aussi des variables d’instances.
- Peut mettre constante de classe.
- Modèle de structure de classe.
Exercices (Non écrit pour le moment)
Gestion de compte en banque. Trois monnaies, le Z
, le S
et le C
avec des taux de change (fixe ou variables ?). Une banque a une monnaie et des frais de change vers les autres monnaies, frais qui ne doivent pas excéder un maximum. Avec un compte on peut ajouter et retirer de l’argent. On peut comparer deux banques pour savoir laquelle est la mieux pour jouer avec un certain type de monnaie. Une banque peut aussi comparer ses clients.
Aller plus loin => rajouter client. Client = humains => possède vrai argent dans devise, peut retirer, ajouter en utilisant un compte, peut obtenir un compte dans une banque, supprimer son compte, etc.
De bonnes classes
Des fournisseurs de services
- Exemple du chat avec attributs pour l’énergie et la faim.
- Mais, ces attributs sont internes au chat. Ce qu’on veut c’est savoir s’il est fatigué/a faim.
- Construire une classe => se demander quels services on doit pouvoir demander à une instance.
- Solution, méthode
hungry?
et tired?
- Tout ça forme l’interface de la classe.
- Pour avoir une bonne interface, rendre certaines méthodes inaccessibles => visibilité.
- Méthodes privées et protégées.
- Visibilité = aide pour le programmeur => rendre privé ce qui doit être privé.
- Nouveau Modèle de structure de classe.
Une histoire d’invariants
- Un objet doit rendre son service bien. Par exemple afficher
28:12:03
, c’est une erreur.
- Pour ça, il doit notamment être dans un état correct (s’il y a un attribut
hour
et que c’est lui qui est affiché, il ne doit pas pouvoir avoir la valeur 28
).
- On doit s’assurer que l’objet garde un état correct de sa création jusqu’à la fin du programme. => Respecter les invariants.
- Lorsque des méthodes modifient des attributs, il y a des chances d’obtenir un objet dans un état incorrect, faire attention à cela.
- Une bonne visibilité aide à conserver les invariants.
- Encapsulation = n’offrir que des services permettant de respecter les invariants.
- Qu’utiliser lorsque nous programmons la classe, attributs ou accesseurs/mutateurs => faire des choix et rester cohérent. Toujours faire attention au respect des invariants.
De bons et loyaux services
- L’objectif est de fournir de bons services : code clair, facile à tester et maintenir.
- Identifier le service, c’est identifier un contrat entre la méthode et son utilisateur : si tu me donnes ça, je te garantis ça => notions de préconditions et de postconditions. Mention du TDD.
- Pour faciliter tout ça, des services simples, donc des méthodes simples. En particulier, une méthode = un service. Mention du SRP.
- Avoir une classe permet de donner du sens à certains objets et à certaines opérations et donc d’avoir un code plus clair. Par exemple, on n’additionne pas les températures et les distances. En particulier, rajout (et respect) d’invariants et de contrats facilités (on ne construit pas d’objets incohérents et nos services les gardent dans des états cohérents).
- Un objet peut être compris comme les services qu’il peut rendre => Duck Typing, une méthode n’attend pas un objet d’une certaine classe, mais juste un objet qui sait rendre les services qu’on lui demandera.
print
par exemple attend juste un objet qui sait s’afficher avec to_s
.
Exercices (Non écrit)
Les modules
Les modules
- On crée un premier module.
- Permet de regrouper des méthodes et des constantes.
- Introduction de
module_function
.
- Les modules sont des espaces de noms.
- On peut inclure un module => analogie avec un tiroir qu’on déverse.
Modules et classes
- Modules semblables aux classes. Que faut-il utiliser ?
- Modules ne sont pas instanciables.
- Modules pour regroupement de méthodes et constantes.
- On peut imbriquer des modules et des classes dans d’autres modules/classes.
- Un fichier par module et par class. Utilisation du fichier avec
require_relative
.
Inclusion de modules
include
indique à Ruby que les méthodes d’instances du module sont maintenant des méthodes d’instances de Object
.
module_function
déclare des méthodes du module, mais aussi des méthodes d’instances, ce qui permet à include
de fonctionner.
- Un peu plus de complexité dans notre algorithme de lookup. Après avoir regardé les méthodes de
Object
, on regarde dans les méthodes des modules qu’on a inclus.
Exercices (En cours d’écriture)
solveur de Sudoku
Des objets plus complexes (non écrit)
Très semblable à la version du chapitre précédemment écrite. Puisque certains points ont déjà été abordé précédemment (on a par exemple introduit de plus en plus d’éléments de l’algorithme de lookup, le *duck typing, la composition, les variables d’instances de classes ont déjà été abordées, etc.) il sera un peu plus léger, ce qui permettra de se concentrer vraiment sur l’héritage et les mixins. Avec les mixins, expliquer que les méthodes puts
et print
sont des méthodes de Kernel
qui est mixé à Object
.
Chapitre TP avec comme objectif les principes SOLID
Gestion de Discographie, (TP honteusement piqué au tutoriel C++ )…
Et le reste (exceptions et blocs) ne change pas trop.
EDIT : plan modifié