La déclaration de constantes et l'utilisation des companion objects sont des concepts importants en Kotlin, qui ont remplacé les membres statiques habituels en Java et les difficultés associées à la traversée des paradigmes de la programmation orientée objet et de la programmation fonctionnelle.
Historique de la question : En Java, les constantes sont généralement des champs static final, et les méthodes statiques sont utilisées pour des fonctions utilitaires ou de fabrication. En Kotlin, à la place de static, on a introduit object et companion object, et pour les constantes de compilation, le mot clé const.
Problème : Il est nécessaire de déclarer des valeurs qui ne dépendent pas d'une instance de classe, ainsi que d'organiser des méthodes de fabrication et un état statique, sans compromettre l'intégrité de la programmation orientée objet.
Solution : Les objets compagnons (companion object) sont déclarés à l'intérieur d'une classe et permettent de placer des membres communs à toutes les instances :
Exemple de code :
class MyClass { companion object { const val DEFAULT_LIMIT = 10 fun create(): MyClass = MyClass() } } val limit = MyClass.DEFAULT_LIMIT val instance = MyClass.create()
Particularités clés :
Un companion object peut-il avoir plusieurs instances dans une classe ?
Non, une classe ne peut avoir qu'un seul companion object. Tenter d'en déclarer un deuxième entraînera une erreur de compilation. Mais à l'intérieur du companion object, tout nombre de méthodes/propriétés est autorisé.
Peut-on initialiser des variables lateinit à l'intérieur du companion object ?
Non, car les propriétés avec const ou les variables à l'intérieur du companion object doivent être initialisées immédiatement ou être val/var avec une initialisation explicite. lateinit n'est pas autorisé pour les propriétés à l'intérieur du companion object.
Un companion object peut-il avoir son propre nom et quand cela est-il nécessaire ?
Oui, le nom du companion object est donné explicitement si l'on souhaite y accéder par nom ou, par exemple, implémenter des interfaces. Dans d'autres cas, il est optionnel. Exemple :
class Foo { companion object Factory { fun create(): Foo = Foo() } } val instance = Foo.Factory.create()
Toute la fonctionnalité auxiliaire et les variables globales du programme sont placées dans le companion object, des var sont utilisées au lieu de val/const :
Avantages :
Inconvénients :
Seules des constantes de compilation (const val) et des fonctions pures sont utilisées à l'intérieur du companion object, tout ce qui est mutable est soit localisé, soit passé par DI :
Avantages :
Inconvénients :