10. Classes

Les widgets que vous allez utiliser (image, champ de texte…) sont des classes d’objets, ainsi que tous les types de valeur. En effet, un int est une classe, un bool est une classe…

Mais comment sont faites les classes en Dart ?

Constructeurs

Pour définir une classe, il faut lui donner des attributs, ils peuvent être des variables ou d’autres classes (objets).

class Knight {
   String name = 'Artorias';
   int life = 10;
}

Ici la classe Knight a deux attributs, un nom et des points de vie. Pour créer une instance de cette classe, il faudra faire le code suivant :

var myKnight = Chevalier();

Nous avons créé un chevalier avec le nom Artorias et 10 points de vie. Mais comment faire si nous voulons instancier avoir un chevalier personnalisé avec un nom et points de vie de notre choix ? Il faudra ajouter un constructeur afin de définir nous même ces données.

class Knight {
 String name;
 int life;

 Knight(this.name, this.life);
}

Et pour créer ce chevalier personnalisé :

var myKnight = Knight('Chevalier au lion', 23);

Si vous souhaitez avoir des valeur par défaut avec la possibilité de les redéfinirs au cas par cas :

class Knight {
 String name;
 int life;

 Knight({this.name = 'Nom par défaut', this.life = 10});
}

La difference ici est la présence de { et } dans le constructeur, qui rend les attributs optionnels et l’ajout de valeurs par défaut.

var myKnight = Knight(name: 'Chevalier au lion', life: 23);

Il est possible d’avoir des attributs optionnels et non optionnels dans le même constructeur.

class Knight {
 String name;
 int life;

 Knight(this.name, {this.life = 10});
}

var myKnight = Knight('Chevalier au lion', life: 23);

Si vous souhaitez avoir affiché le nom des attributs à donner a la classe tout en les ayant en non optionnels, ils vous faudra rajouter required devant chaque attribut dans le constructeur.

Knight({required this.name, required this.life = 10});

Et pour finir cette partie sur les constructeurs, il est possible d’avoir un constructeur optionnel non nommé.

Knight([this.name, this.life]);

Qui sera utilisé de cette maniere :

var myKnight = Knight('Chevalier au lion', 23);
//ou
var myKnight = Knight();

Getter

Il est possible de mettre en place des propriétés qui sont définies lors de leur appel, dans notre cas, on pourrai par exemple détecter si le chevalier est vivant ou non.

class Knight {
 String name;
 int life;
 Knight(this.name, this.life);

 bool get isAlive => life > 0;
}

Heritage

Dart étant un langage POO il est possible de mettre en place un systeme d’heritage. Pour notre exemple de chevalier, on va par exemple pouvoir mettre en place une classe “parent” qui comportera les fonctions basiques comme marcher, attaquer… qui sera applicable aussi bien au chevalier qu’aux ennemies.

Flutter

Cette héritage s’écrira de la façon suivante :

void main() {
 var chevalier = Knight("Artorias", 10);
 var squelette = Skeleton("Roger", 1);

 chevalier.attack();
 squelette.walk();
}

class Knight extends Character {
 String name;
 int life;

 Knight(this.name, this.life);
}

class Skeleton extends Character {
 String name;
 int life;

 Skeleton(this.name, this.life);
}

class Character {
 void attack() {
 print('Le personnage attaque.');
 }

 void walk() {
 print('Le personnage marche.');
 }
}

On peut remarquer que les deux personnages ont un nom et un nombre de points de vie. On peut alors appliquer ces attributs à la classe Character et ainsi limiter la duplication de code. Cela est fait en supprimant le constructeur des classes “enfant” et en le déplaçant dans la classe “parent” et en utilisant le mot clé super qui permet de transmettre les attributs à la classe “parent”. On peut s’en rendre compte en utilisant la fonction print sur les fonctions de marche et d’attaque en y intégrant le nom du personnage.

void main() {
 var chevalier = Knight("Artorias", 10);
 var squelette = Skeleton("Roger", 1);

 chevalier.attack();
 squelette.walk();
}

class Knight extends Character {
 Knight(String name, int life) : super(name, life);
}

class Skeleton extends Character {
 Skeleton(String name, int life) : super(name, life);
}

class Character {
 String name;
 int life;

 Character(this.name, this.life);

 void attack() {
 print('$name attaque.');
 }

 void walk() {
 print('$name marche.');
 }
}

Un dernier point sur cette leçon sur les classes en Dart, la surcharge de fonction. Nous avons nos deux personnages, ils savent faire la même chose, mais imaginons qu’une action soit différente sur l’un des personnages ?

Il est possible de surchargé ( override) une fonction de la classe Character en écrivant la meme fonction avec l’annotation @override avant la fonction. Ensuite, il suffira de changer le contenu et le personnaliser pour le personnage.

class Knight extends Character {
 Knight(String name, int life) : super(name, life);

 @override
 void attack() {
 print('$name attaque avec son épée.');
 }
}