Menu
Coddy logo textTech

Objets compagnons

Fait partie de la section Programmation orientée objet du Journey Kotlin de Coddy. Leçon 13 sur 57.

Certains membres appartiennent à une classe dans son ensemble plutôt qu’à une seule instance. Kotlin les place dans un companion object à l’intérieur de la classe, et vous les appelez via le nom de la classe :

class Temperature(val celsius: Double) {
    companion object {
        fun fromFahrenheit(f: Double) = Temperature((f - 32) * 5 / 9)
    }
}

À l’intérieur de main :

val boiling = Temperature.fromFahrenheit(212.0)
println(boiling.celsius)

Résultat :

100.0

fromFahrenheit est une fonction fabrique : une fonction qui crée des instances. Contrairement à un constructeur, elle possède un nom descriptif et peut renvoyer null au lieu d’un objet. Avec un private constructor, la fabrique est le seul point d’accès ; elle peut donc d’abord vérifier et nettoyer l’entrée :

class Username private constructor(val text: String) {
    companion object {
        fun of(raw: String): Username? {
            val clean = raw.trim().lowercase()
            return if (clean.length in 3..12) Username(clean) else null
        }
    }
}

Dans main :

println(Username.of("  Ada_L ")?.text)
println(Username.of("x")?.text)
// Username("x")   // erreur : le constructeur est privé

Sortie :

ada_l
null

L’objet compagnon appartient à la classe, il peut donc appeler le constructeur privé, et le code propre à la classe utilise les membres du compagnon sans préfixe. Ici, chaque billet prend le nombre suivant d’un compteur partagé par tous les billets :

class Ticket(val holder: String) {
    val number = nextNumber++

    companion object {
        private var nextNumber = 1
        val issued: Int
            get() = nextNumber - 1
    }
}

À l’intérieur de main :

val a = Ticket("Ada")
val b = Ticket("Bo")
println("${a.holder} #${a.number}, ${b.holder} #${b.number}")
println("issued: ${Ticket.issued}")

Sortie :

Ada #1, Bo #2
issued: 2

Kotlin n’a pas de mot-clé static. Les membres du compagnon jouent ce rôle : une seule copie pour toute la classe, accessible avec ClassName.member. Comme tout objet, le compagnon est créé une seule fois, lorsque la classe est utilisée pour la première fois. Placez-y ce qui ne dépend pas d’une instance, comme les fabriques et les compteurs partagés ; tout ce qui lit les données d’une instance reste un membre normal.

class User private constructor(val name: String) {
    fun greet() = "hi $name"             // nécessite une instance : user.greet()

    companion object {
        fun guest() = User("guest")      // appartient à la classe : User.guest()
    }
}
challenge icon

Défi

Facile

Complétez la classe Coupon. Son constructeur est privé, les coupons sont donc créés par la fabrique Coupon.create(code, percent) dans l’objet compagnon. Elle renvoie null sauf si le code comporte de 4 à 10 caractères constitués de lettres majuscules et de chiffres, et si le pourcentage est compris entre 1 et 90. L’objet compagnon compte également les coupons qu’il a créés dans created, que le code externe peut lire, mais pas modifier. apply(price) renvoie le prix diminué de la remise, arrondi à l’entier inférieur (price * (100 - percent) / 100).

Le code fourni lit des lignes SAVE10 10 200 (code, pourcentage, prix). Il affiche SAVE10: 180 ou invalid coupon SAVE10, puis enfin created: suivi du nombre.

Votre code doit être placé dans Coupon.kt. Main.kt contient le code fourni pour les entrées et les sorties et ne peut pas être modifié.

Essayez vous-même

fun main() {
    // Code d'entrée/sortie fourni : le garder tel quel
    val input = generateSequence(::readLine).toList()
    for (line in input) {
        val (code, percent, price) = line.split(" ")
        val coupon = Coupon.create(code, percent.toInt())
        if (coupon == null) println("invalid coupon $code") else println("${coupon.code}: ${coupon.apply(price.toInt())}")
    }
    println("created: ${Coupon.created}")
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Playground Kotlin