Introduction à Scala : Les Traits

[Scala]Dans ce quatrième volet de la série “Introduction à Scala”, je vais présenter la notion des traits dans Scala, qui sont ce qui ressemble le plus aux interfaces de Java.

1. Présentation

La définition d’un trait en Scala se présente comme suit:

 
trait nom [extends un-trait | une-classe [with un-autre-trait ...] ]

Ici, ce qui est entre [ ] dénote un élément optionnel, le | indique que l’une ou l’autre des alternative est applicable, et indique que ce qui précède peut être répété à volonté.

Bref, le plus important c’est le mot clé “trait“, qui la différencie d’une classe ordinaire.

Voici un exemple d’un trait:

Code Scala

Ici, j’ai défini un trait nommé Action qui contient une seule méthode abstraite action.

Voici maintenant une classe qui étend ce trait :

Code Scala

Veuillez noter qu’une classe peut étendre plusieurs traits, et ce en utilisant le mot clé with à partir du second tait étendu, comme montré dans l’exemple suivant:

Code Scala

2. Les traits comme des interfaces

Dans une première approche, on peut utiliser les traits de Scala pour émuler les interfaces de Java, en limitant leur rôle à la définition des contrats des classes.

A titre d’exemple, considérons ce bout de code :

Code Scala

J’ai commencé par définir un trait Age pour représenter une entité ayant un âge, d’où la méthode abstraite age.
J’ai ensuite défini un trait Comparable qui contient quelques méthodes permettant de comparer deux entités ayant un âge comme sameAge, olderThan, etc.

A la fin, j’ai implémenté ces deux traits dans une classe Person.

3. Les traits pour simplifier l’implémentation

La tache des classes implémentant le trait Comparable peut être grandement simplifié quand on sait que plusieurs méthodes du trait Comparable peuvent être déduites de deux autres méthodes de ce même trait.
Par exemple, si on suppose disposer de sameAge et olderThan, on peut donc déduire le reste des méthodes :
- youngerThan est alors !olderThan(that) && !sameAge(that)
- etc.

Les traits Scala, et à l’inverse des interfaces de Java, peuvent avoir des champs et implémenter des méthodes.
En tirant profit des deux points précédents, on peut ré-écrire l’exemple précédent en :

Code Scala

Ainsi, il suffit d’implémenter 2 méthodes des 5 définies par Comparable pour avoir une implémentation complète.

4. Utiliser les traits comme décorateurs

Un autre utilisation possible des itérateurs serait des les combiner à une classe donnée en tant que décorateurs, apportant de nouvelles fonctionnalités ou modifiant les fonctionnalités existantes.

Pour illustrer ce concept, commençons par définir un trait représentant une opération quelconque :

Code Scala

Ainsi qu’une implémentation bidon, qui lance ou non, et de façon aléatoire une exception :

Code Scala

Je vais commencer par un décorateur simple, qui ne fait qu’afficher un message avant l’exécution de l’action concrète et un autre après sa fin.
Un tel décorateur se définit comme un trait ordinaire, avec quelques points à respecter :
- Il doit hériter du trait définissant l’action (Action)
- Il doit implémenter la méthode du trait parent, tout en déclarant cette implémentation comme abstraite, pour s’assurer que la classe d’implémentation concrète définisse bel et bien l’action réelle.
- L’implémentation réelle de l’action peut alors être référencée par super.action() dans le trait de décoration.

En suivant ces règles, le trait de logging s’écrit alors :

Code Scala

Maintenant, pour combiner ce décorateur à l’action concrète, on procède comme suit :

Code Scala

Notez l’instanciation de l’action concrète suivie du mot clé with et du nom de du trait décorateur.

A l’exécution, on obtient :

before action 
TestAction 
after action 

On peut dès lors imaginer toute sorte de décorateurs, comme par exemple un décorateur qui répète N fois l’action tant qu’elle lance une exception :

Code Scala

Ou encore un décorateur qui rend l’exécution synchronisée :

Code scala

Enfin, on peut associer une classe donnée à plusieurs traits de décoration comme suit :

Code Scala

Notez que l’ordre de l’apparence d’un trait dans l’instanciation influe sur son ordre à l’exécution : le premier trait qui apparaît serait le dernier à être exécuté, et ainsi de suite.
Dans tous les cas de figure, la classe concrète serait exécutée en dernier.

Ainsi, dans l’exemple précédent, l’ordre d’exécution serait :

1. RetryNTimesAction 
2. LoggedAction 
3. SynchronizedAction 
4. TestAction. 

Conclusion

Dans ce volet de l’introduction à Scala, j’ai présenté les traits via quelques cas d’utilisations courants.
N’hésitez surtout pas à me communiquer vos impressions, critiques et propositions et ce en commentant dans ce même blog, ou via messages privés (via forum).

—-

About these ads

One Response to Introduction à Scala : Les Traits

  1. Loic says:

    Super article, merci beaucoup

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: