La dichiarazione delle costanti e l'uso degli oggetti companion sono concetti importanti di Kotlin, che hanno sostituito i classici membri statici di Java e le difficoltà associate all'intersezione tra le paradigmi della programmazione orientata agli oggetti e della programmazione funzionale.
Contesto: In Java, per le costanti si utilizzano solitamente campi statici finali, mentre i metodi statici sono utilizzati per funzioni di utilità o di fabbrica. In Kotlin, invece di statico, sono stati introdotti object e companion object, e per le costanti a tempo di compilazione — la parola chiave const.
Problema: È necessario dichiarare valori che non dipendono dall'istanza della classe e organizzare metodi di fabbrica e stati statici senza compromettere l'integrità dell'OOP.
Soluzione: Gli oggetti companion (companion object) vengono dichiarati all'interno di una classe e consentono di posizionare membri comuni a tutte le istanze:
Esempio di codice:
class MyClass { companion object { const val DEFAULT_LIMIT = 10 fun create(): MyClass = MyClass() } } val limit = MyClass.DEFAULT_LIMIT val instance = MyClass.create()
Caratteristiche principali:
Può un oggetto companion avere più istanze nella classe?
No, in una classe può esserci solo un oggetto companion. Tentare di dichiararne uno secondo porterà a un errore di compilazione. Tuttavia, all'interno dell'oggetto companion è consentito avere qualsiasi numero di metodi/proprietà.
È possibile inizializzare variabili lateinit all'interno di un oggetto companion?
No, perché le proprietà con const o le variabili all'interno dell'oggetto companion devono essere inizializzate immediatamente o devono essere val/var con inizializzazione esplicita. La parola chiave lateinit non è consentita per le proprietà all'interno dell'oggetto companion.
L'oggetto companion può avere un proprio nome e quando è necessario?
Sì, il nome dell'oggetto companion è specificato esplicitamente, se è necessario riferirsi ad esso per nome o, ad esempio, per implementare interfacce. In altri casi, è facoltativo. Esempio:
class Foo { companion object Factory { fun create(): Foo = Foo() } } val instance = Foo.Factory.create()
Tutta la funzionalità ausiliaria e le variabili globali del programma vengono collocate nell'oggetto companion, utilizzando var invece di val/const:
Vantaggi:
Svantaggi:
Vengono utilizzate solo costanti a tempo di compilazione (const val) e funzioni pure all'interno dell'oggetto companion, tutto ciò che è mutabile è localizzato o passato tramite DI:
Vantaggi:
Svantaggi: