Implémentation du carnet d'adresses

Maintenant que nous avons les classes Adresse et Personne, il ne nous reste plus qu’à créer la classe Carnet.

Première étape

Notre carnet d’adresse doit contenir un tableau, qui contient tous nos contacts. Nous n’utiliserons pas attr_accessor parce que nous ne voulons pas qu’on puisse accéder directement au tableau. Nous allons donc écrire nos propres méthodes pour travailler sur le tableau interne.

Voici à quoi peut ressembler le code de notre classe Carnet:


 class Carnet 
    def initialize
        # Initialise le tableau.  Meme chose que ``Array.new''.  
        @personnes = []
    end
 end

C’était plutot facile. Rajoutons maintenant deux méthodes d’accès: Carnet#ajoute et Carnet#retire:


 class Carnet 
    def initialize
        @personnes = []
    end
    def ajoute(personne)
        1
        @personnes.push(personne)
    end
    def retire(personne)
        2
        @personnes.delete(personne)
    end
 end

Explication du code:

  1. La méthode Array#push permet d’ajouter un objet dans un tableau. L’objet sera empilé sur les objets existants, un peu comme si vous rajoutiez une assiette sur une pile d’assiettes.
  2. La méthode Array#delete permet de supprimer un objet d’un tableau. Si le tableau contient plusieurs objets identiques, ils seront tous supprimés.

Pour mieux comprendre le fonctionnement de Array#delete, essayez ceci dans IRB :

 >> a = [ 1, 3, 3, 3, 3, 5]  
 => [1, 3, 3, 3, 3, 5]
 >> a.delete(3)
 => 3
 >> a
 => [1, 5]

Tri automatique

Nous allons maintenant rajouter une super fonctionnalité dans notre Carnet: un tri automatique. Par exemple, imaginez le code suivant:


 carnet = Carnet.new
 carnet.ajoute nicolas 
 carnet.ajoute francois
 carnet.ajoute marina 

Le carnet classera automatiquement les personnes à chaque ajout. Cette fonctionnalité va rendre notre classe Carnet bien plus intéressante qu’un simple tableau. Comment trier un tableau?

Nous voulons que le tableau contenant les contacts soit trié par ordre alphabétique, en se basant sur le nom complet de la personne (prénom et nom de famille). Dans la section précédente, nous avons écrit ceci :


 # ``carnet'' est un tableau ici
 carnet.sort do |personne_a, personne_b|
    personne_a["prénom"] <=> personne_b["prénom"]
 end

Adaptons ce code pour notre classe Carnet:


 @personnes.sort do |a, b|
    a.prenom <=> b.prenom
 end

Si vous avez effectué les exercices du chapitre précédent, vous devriez déjà savoir comment trier les personnes en se basant sur leur nom complet. Voici une façon de le faire :


 @personnes.sort do |a, b|
    if a.prenom == b.prenom
        a.nom <=> b.nom
    else
        a.prenom <=> b.prenom
    end
 end

Si les prénoms sont les mêmes, nous comparons les noms de famille. Sinon, on compare les prénoms.

Simplification

Le principe fondamental de la simplification est de diviser le problème en petites parties. Nous pouvons déplacer le bloc de code dans une méthode :


 def par_nom(a, b)
    if a.prenom == b.prenom
        a.nom <=> b.nom
    else
        a.prenom <=> b.prenom
    end
 end

Maintenant, nous pouvons écrire: @personnes.sort do |a, b| par_nom(a, b) end

Ce qui est beaucoup plus simple à lire.

Astuce : Il est possible de définir avec Ruby des blocs de code en utilisant deux syntaxes différentes:


 @personnes.sort do |a, b|
    # ...
 end

 @personnes.sort { |a, b|
    # ...
 }

Ces deux notations veulent dire exactement la même chose. La différence est que do … end est plus lisible, et que { ... } est plus court.

Nous pouvons écrire le tri de notre tableau de cette façon:

@personnes.sort { |a, b| par_nom(a, b) }

Vous pouvez litéralement lire «tri de personnes par le nom». C’est du code très lisible. Voici une suggestion:

  • Utilisez la notation { ... } quand il est possible de faire tenir l’expression sur une seule ligne.
  • Sinon, utilisez do … end.

Finalement

Il est maintenant temps de déplacer ce code dans notre classe Carnet, et d’implémenter notre tri automatique:


 class Carnet 
    def initialize
        @personnes = []
    end
    def ajoute(personne)
        @personnes.push(personne)
        @personnes = @personnes.sort { |a, b| par_nom(a, b) }
    end
    def retire(personne)
        @personnes.delete(personne)
    end
    def par_nom(a, b)
        if a.prenom == b.prenom
            a.nom <=> b.nom
        else
            a.prenom <=> b.prenom
        end
    end
 end

Maintenant, à chaque fois que vous ajouterez une personne dans le carnet, ce dernier sera trié automatiquement !

Plus de classes << | Apprenez Ruby | >> Écrire des itérateurs