Kotlin From Scratch classes abstraites, interfaces, héritage et pseudonyme

Kotlin est un langage de programmation moderne qui compile en bytecode Java. C'est gratuit et open source, et promet de rendre le codage pour Android encore plus amusant.  

Dans l'article précédent, vous en avez appris davantage sur les propriétés de Kotlin, telles que les propriétés d'initialisation tardive, d'extension et en-ligne. De plus, vous avez également découvert les classes avancées telles que les classes data, enum, imbriquées et scellées dans Kotlin.. 

Dans cet article, vous allez continuer à vous familiariser avec la programmation orientée objet dans Kotlin en vous renseignant sur les classes abstraites, les interfaces et l'héritage. Pour un bonus, vous apprendrez également sur les alias de type. 

1. Cours abstraits

Kotlin supporte les classes abstraites - tout comme Java, ce sont des classes pour lesquelles vous n'avez jamais l'intention de créer des objets. Une classe abstraite est incomplète ou inutile sans certaines sous-classes concrètes (non abstraites), à partir desquelles vous pouvez instancier des objets. Une sous-classe concrète d'une classe abstraite implémente toutes les méthodes et propriétés définies dans la classe abstraite. Sinon, la sous-classe est également une classe abstraite.!

Nous créons une classe abstraite avec le abstrait modificateur (similaire à Java). 

Classe abstraite Employé (val firstName: String, val lastName: String) résumé amusant gains (): Double

Notez que tous les membres ne doivent pas nécessairement être abstraits. En d'autres termes, nous pouvons avoir une implémentation par défaut de la méthode dans une classe abstraite. 

classe abstraite Employé (val firstName: String, val lastName: String) //… fun nom complet (): String return lastName + "" + firstName; 

Ici nous avons créé la fonction non abstraite nom complet() dans une classe abstraite Employé. Les classes concrètes (sous-classes de la classe abstraite) peuvent redéfinir l'implémentation par défaut d'une méthode abstraite, mais uniquement si la méthode a ouvrir modificateur spécifié (vous en apprendrez plus à ce sujet prochainement). 

Nous pouvons également stocker l'état dans des classes abstraites. 

Classe abstraite Employé (val firstName: String, val lastName: String) //… val propFoo: String = "bla bla"

Même si la classe abstraite ne définit aucune méthode, nous devons créer une sous-classe avant de pouvoir l'instancier, comme dans l'exemple ci-dessous..

programmeur de classe (prénom: chaîne, nom de famille: chaîne): employé (prénom, nom de famille) ignore les gains intéressants (): double // calcule les gains

Notre Programmeur la classe étend la Employé classe abstraite. En Kotlin, nous utilisons un seul caractère deux-points (:) au lieu de Java s'étend mot clé pour étendre une classe ou implémenter une interface. 

On peut alors créer un objet de type Programmeur et appelez des méthodes dessus, soit dans sa propre classe, soit dans la superclasse (classe de base).  

val programmer = Programmeur ("Chike", "Mgbemena") println (programmer.fullName ()) // "Mgbemena Chike"

Une chose qui pourrait vous surprendre est que nous avons la possibilité de passer outre un val (immuable) propriété avec var (mutable). 

classe ouverte BaseA (open val baseProp: String)  classe DerivedA: BaseA ("") var privée private DeriveProp: String = "" substitue var BaseProp: String get () = DeriveProp set (valeur) DerileProp = valeur

Assurez-vous d'utiliser cette fonctionnalité à bon escient! Sachez que nous ne pouvons pas inverser la priorité var propriété avec val

2. Interfaces

Une interface est simplement un ensemble de méthodes associées qui vous permettent généralement d'indiquer aux objets ce qu'ils doivent faire et comment le faire par défaut. (Les méthodes par défaut dans les interfaces sont une nouvelle fonctionnalité ajoutée à Java 8.) En d'autres termes, une interface est un contrat que les classes d'implémentation doivent respecter.. 

Une interface est définie en utilisant le interface mot clé en Kotlin (similaire à Java). 

class Résultat class Interface étudiant StudentRepository fun getById (id: long): étudiant fun getResultsById (id: long): List 

Dans le code ci-dessus, nous avons déclaré StudentRepository interface. Cette interface contient deux méthodes abstraites: getById () et getResultsById (). Notez que, y compris le abstrait le mot clé est redondant dans une méthode d'interface car ils sont déjà abstraites de manière implicite. 

Une interface est inutile sans un ou plusieurs implémenteurs. Créons donc une classe qui implémentera cette interface.. 

class StudentLocalDataSource: StudentRepository annule fun getResults (id: Long): List // do implementation remplacez fun getById (id: Long): Étudiant // do implementation

Ici nous avons créé une classe StudentLocalDataSource qui met en œuvre le StudentRepository interface.

Nous utilisons le passer outre modificateur pour étiqueter les méthodes et les propriétés que nous voulons redéfinir à partir de l’interface ou de la super-classe. @Passer outre annotation en Java.

Notez les règles supplémentaires suivantes concernant les interfaces dans Kotlin:

  • Une classe peut implémenter autant d'interfaces que vous le souhaitez, mais elle ne peut étendre qu'une seule classe (similaire à Java).
  • le passer outre modificateur est obligatoire dans Kotlin, contrairement à Java. 
  • En plus des méthodes, nous pouvons également déclarer des propriétés dans une interface Kotlin. 
  • Une méthode d'interface Kotlin peut avoir une implémentation par défaut (similaire à Java 8). 

Voyons un exemple de méthode d'interface avec une implémentation par défaut.

interface StudentRepository //… fun delete (student: Student) // implémentation

Dans le code précédent, nous avons ajouté une nouvelle méthode effacer() avec une implémentation par défaut (bien que je n'aie pas ajouté le code d'implémentation réel à des fins de démonstration). 

Nous avons également la liberté de remplacer l'implémentation par défaut si nous voulons.

class StudentLocalDataSource: StudentRepository //… remplace fun delete (student: Student) // implémentation

Comme indiqué, une interface Kotlin peut avoir des propriétés, mais notez qu'elle ne peut pas maintenir l'état. (Cependant, n'oubliez pas que les classes abstraites peuvent conserver l'état.) Ainsi, la définition d'interface suivante avec une déclaration de propriété fonctionnera.

interface StudentRepository val propFoo: Boolean // fonctionnera // //

Mais si nous essayons d'ajouter un état à l'interface en attribuant une valeur à la propriété, cela ne fonctionnera pas.

interface StudentRepository val propFoo: Boolean = true // Erreur: les initialiseurs de propriétés ne sont pas autorisés dans les interfaces //…

Cependant, une propriété d'interface dans Kotlin peut avoir des méthodes getter et setter (bien que cette dernière option uniquement si la propriété est mutable). Notez également que la propriété dans une interface ne peut pas avoir un champ de sauvegarde. 

interface StudentRepository var propFoo: Boolean get () = true set (valeur) if (valeur) // faire quelque chose //…

Nous pouvons également redéfinir une propriété d'interface si vous le souhaitez, afin de la redéfinir. 

class StudentLocalDataSource: StudentRepository //… substitue var propFoo: Boolean get () = false set (valeur) if (valeur) 

Regardons le cas où une classe implémente plusieurs interfaces avec la même signature de méthode. Comment la classe décide-t-elle quelle méthode d'interface appeler?

interface InterfaceA fun funD ()  interfaceB fun funD () 

Ici, nous avons deux interfaces qui ont une méthode avec la même signature fonds(). Créons une classe qui implémente ces deux interfaces et remplace la fonds() méthode. 

class classA: InterfaceA, InterfaceB override fun funD () super.funD () // Erreur: de nombreux super-types disponibles, veuillez spécifier celui que vous voulez dire entre crochets, p. ex. 'super'

Le compilateur ne sait pas comment appeler le super.funD () méthode car les deux interfaces implémentées par la classe ont la même signature de méthode. 

Pour résoudre ce problème, nous encapsulons le nom de l'interface pour laquelle nous voulons appeler la méthode entre crochets . (IntelliJ IDEA ou Android Studio vous donneront un indice sur la façon de résoudre ce problème quand il se présentera.)

classe classA: InterfaceA, InterfaceB override fun funD () super.funD ()

Ici, nous allons appeler le fonds()  méthode de InterfaceA. Problème résolu! 

3. Héritage

Une nouvelle classe (sous-classe) est créée en acquérant les membres d'une classe existante (superclasse) et éventuellement en redéfinissant leur implémentation par défaut. Ce mécanisme est appelé héritage en programmation orientée objet (OOP). Ce qui rend Kotlin si impressionnant, c’est qu’il englobe à la fois les paradigmes de programmation orientée objet et de programmation fonctionnelle, le tout dans un seul langage..

La classe de base pour toutes les classes de Kotlin est Tout

classe Personne: N'importe lequel 

le Tout le type est équivalent à Objet type que nous avons en Java. 

public open class Any opérateur public ouvert fun est égal à (autre: Any?): Booléen public open fun hashCode (): Int public ouvert fun toString (): String

le Tout type contient les membres suivants: équivaut à(), hashcode (), et aussi toString () méthodes (similaire à Java). 

Nos classes n'ont pas besoin d'étendre explicitement ce type. Si vous ne spécifiez pas explicitement quelle classe une nouvelle classe étend, la classe s'étend Tout implicitement. Pour cette raison, vous n'avez généralement pas besoin d'inclure : Tout dans votre code, nous le faisons dans le code ci-dessus à des fins de démonstration. 

 Voyons maintenant comment créer des classes dans Kotlin en gardant à l'esprit l'héritage.. 

classe Student  classe GraduateStudent: Student () 

Dans le code ci-dessus, le Étudiant diplomé la classe étend la superclasse Étudiant. Mais ce code ne compilera pas. Pourquoi? Parce que les classes et les méthodes sont final par défaut dans Kotlin. En d'autres termes, elles ne peuvent pas être étendues par défaut, contrairement à Java où les classes et les méthodes sont ouvertes par défaut.. 

Les meilleures pratiques en matière de génie logiciel vous recommandent de commencer à créer vos classes et méthodes. final par défaut, c'est-à-dire. si elles ne sont pas spécifiquement destinées à être redéfinies ou remplacées dans des sous-classes. L’équipe de Kotlin (JetBrains) a appliqué cette philosophie de codage et de nombreuses autres meilleures pratiques de développement pour développer ce langage moderne.. 

Pour permettre la création de sous-classes à partir d’une superclasse, nous devons explicitement marquer la superclasse avec le signe ouvrir modificateur. Ce modificateur s'applique également à toute propriété ou méthode de superclasse qui doit être remplacée par des sous-classes..

classe ouverte étudiant 

Nous mettons simplement le ouvrir modificateur avant le classe mot-clé. Nous avons maintenant demandé au compilateur de permettre à notre Étudiant la classe doit être ouverte pour l'extension. 

Comme indiqué précédemment, les membres d'une classe Kotlin sont également définitifs par défaut. 

classe ouverte Student open fun schoolFees (): BigDecimal // do implementation

Dans le code précédent, nous avons marqué le frais de scolarité fonctionne comme ouvrir-afin que les sous-classes puissent le remplacer. 

classe ouverte GraduateStudent: Student () remplace fun schoolFees (): BigDecimal return super.schoolFees () + CalculateSchoolFees () fun privé CalculateSchoolFees (): BigDecimal // calcule et retourne les frais de scolarité

Ici, l'ouvert frais de scolarité fonction de la superclasse Étudiant est remplacé par le Étudiant diplomé classe en ajoutant le passer outre modificateur avant le amusement mot-clé. Notez que si vous substituez un membre d’une superclasse ou d’une interface, le membre substituant sera également ouvrir Par défaut, comme dans l'exemple ci-dessous:

class ComputerScienceStudent: GraduateStudent () substitue fun schoolFees (): BigDecimal return super.schoolFees () + CalculateSchoolFess () fun privé CalculateSchoolFess (): BigDecimal // calcule et retourne les frais de scolarité

Même si nous n'avons pas marqué le frais de scolarité() méthode dans le Étudiant diplomé classe avec le ouvrir modificateur, nous pouvons toujours le remplacer-comme nous l'avons fait dans le ComputerScienceStudent classe. Pour que cela soit évité, nous devons marquer le membre dominant comme final

N'oubliez pas que nous pouvons ajouter de nouvelles fonctionnalités à une classe, même si celle-ci est définitive, en utilisant des fonctions d'extension dans Kotlin. Pour un rappel sur les fonctions d'extension, consultez mes fonctions avancées dans la publication Kotlin. De plus, si vous avez besoin d’un rappel sur la façon de donner même à une classe finale de nouvelles propriétés sans en hériter, lisez la section sur les propriétés d’extension dans la section Mes propriétés et classes avancées.. 

Si notre super-classe a un constructeur primaire comme celui-ci:

classe ouverte Student (val firstName: String, val lastName: String) //…

Ensuite, toute sous-classe doit appeler le constructeur principal de la superclasse. 

classe ouverte GraduateStudent (prénom: chaîne, nom de famille: chaîne): étudiant (prénom, nom de famille) //…

Nous pouvons simplement créer un objet du Étudiant diplomé classe comme d'habitude:

val graduStudent = GraduateStudent ("Jon", "Snow") println (graduStudent.firstName) // Jon

Si la sous-classe veut appeler le constructeur de la super-classe à partir de son constructeur secondaire, nous utilisons le super mot-clé (similaire à la façon dont les constructeurs de super-classes sont appelés en Java). 

classe ouverte GraduateStudent: Student //… thèse privée privée: String = "" constructeur (prénom: String, nom: String, thèse: String): super (prénom, nom) this.thesis = thèse

Si vous avez besoin d'un rappel sur les constructeurs de classes à Kotlin, veuillez visiter mon post Classes and Objects. 

4. Bonus: type alias

Une autre bonne chose à faire à Kotlin est de donner à un type un alias. 

Voyons un exemple.

Classe de données Person (val firstName: String, val lastName: String, val age: Int)

Dans la classe ci-dessus, nous pouvons assigner le Chaîne et Int types pour le La personne alias de propriétés à l'aide du typealias modificateur à Kotlin. Ce modificateur est utilisé pour créer un alias de n'importe quel type dans Kotlin, y compris ceux que vous avez créés.. 

typealias Nom = Chaîne typealias Age = Int Classe de données Personne (val firstName: Name, val lastName: Nom, val age: Age) 

Comme vous pouvez le constater, nous avons créé un alias prénom et Âge pour les deux Chaîne et Int types respectivement. Nous avons maintenant remplacé le Prénom et nom de famille type de propriété à notre alias prénom-et aussi Int taper à Âge alias. Notez que nous n’avons créé aucun nouveau type. Nous avons plutôt créé un alias pour les types.. 

Celles-ci peuvent être pratiques lorsque vous souhaitez fournir une meilleure signification ou sémantique aux types de votre base de code Kotlin. Alors utilisez-les judicieusement! 

Conclusion

Dans ce tutoriel, vous en avez appris plus sur la programmation orientée objet de Kotlin. Nous avons couvert les points suivants:

  • classes abstraites
  • interfaces 
  • héritage
  • type alias

Si vous avez appris Kotlin à travers notre série Kotlin From Scratch, assurez-vous d’avoir tapé le code que vous voyez et de l’avoir exécuté sur votre IDE. Un bon conseil pour bien comprendre un nouveau langage de programmation (ou tout concept de programmation) que vous apprenez est de vous assurer de ne pas simplement lire la ressource pédagogique ou le guide, mais également de saisir le code et de l'exécuter.!

Dans le prochain tutoriel de la série Kotlin From Scratch, vous découvrirez la gestion des exceptions dans Kotlin. À bientôt!

Pour en savoir plus sur la langue Kotlin, je vous recommande de consulter la documentation Kotlin. Ou consultez certains de nos autres articles sur le développement d'applications Android ici sur Envato Tuts!