Classi e istanze di oggetti in Kotlin

Per i codelab in questo percorso, creerai un'app Android Dice Roller. Quando l'utente "tira i dadi", viene generato un risultato casuale. Il risultato tiene conto del numero di lati dei dadi. Ad esempio, solo i valori da 1 a 6 possono essere tirati da un dado a sei facce.

Ecco come si presenta l'app finale.

Per concentrarti sui nuovi concetti di programmazione per questa app, utilizzerai lo strumento di programmazione Kotlin basato su browser per creare funzionalità di base dell'app. Il programma trasmetterà i risultati alla console. In seguito implementerai l'interfaccia utente in Android Studio.

In questo primo codelab, creerai un programma Kotlin che simula i dadi a rotazione e restituisce un numero casuale, proprio come farebbe un dado.

Prerequisiti

  • Come aprire, modificare ed eseguire il codice in https://try.kotlinlang.org/
  • Crea ed esegui un programma Kotlin che utilizza variabili e funzioni e stampa un risultato nella console.
  • Formattare i numeri all'interno del testo utilizzando un modello di stringa con la notazione ${variable}.

Obiettivi didattici

  • Come generare in modo programmatico numeri casuali per simulare il lancio di dadi.
  • Come strutturare il codice creando una classe Dice con una variabile e un metodo.
  • Come creare un'istanza oggetto di una classe, modificare le relative variabili e chiamare i relativi metodi.

Cosa devi creare

  • Un programma Kotlin nello strumento di programmazione Kotlin basato su browser che può eseguire un tiro di dado casuale.

Cosa serve

  • Un computer con una connessione a Internet

I giochi spesso hanno un elemento casuale. Puoi guadagnare un premio casuale o avanzare un numero casuale di passi sul tabellone. Nella tua vita di tutti i giorni, puoi utilizzare numeri e lettere casuali per generare password più sicure.

Invece di girare dadi reali, puoi scrivere un programma che simula il lancio di dadi per te. Ogni volta che lancia i dadi, il risultato può essere qualsiasi numero compreso nell'intervallo di valori possibili. Fortunatamente non devi creare un generatore di numeri casuali per questo programma. La maggior parte dei linguaggi di programmazione, incluso Kotlin, dispone di un metodo integrato per generare numeri casuali. In questa attività utilizzerai il codice Kotlin per generare un numero casuale.

Configura il tuo codice di avvio

  1. Nel browser, apri il sito web https://try.kotlinlang.org/.
  2. Elimina tutto il codice esistente nell'editor di codice e sostituiscilo con quello di seguito. Questa è la funzione main() con cui hai lavorato nei codelab precedenti (vedi Scrivere il tuo primo codelab in Kotlin).
fun main() {

}

Utilizzare la funzione casuale

Per lanciare un dado, devi avere un modo per rappresentare tutti i valori validi del lancio di dadi. Per un normale dado a 6 facce, i tiri da dado accettabili sono: 1, 2, 3, 4, 5 e 6.

Nella versione precedente hai appreso che esistono tipi di dati, ad esempio Int, per i numeri interi e String per i testi. IntRange è un altro tipo di dati e rappresenta un intervallo di numeri interi da un punto di partenza a un endpoint. IntRange è un tipo di dati adatto per rappresentare i possibili valori che può generare un tiro di dado.

  1. All'interno della funzione main(), definisci una variabile come val chiamata diceRange. Assegnalo a un IntRange da 1 a 6, che rappresenta l'intervallo di numeri interi che un dado a sei facce può tirare.
val diceRange = 1..6

Puoi stabilire che 1..6 è un intervallo di Kotlin perché contiene un numero iniziale, due punti, seguito da un numero finale (senza spazi). Altri esempi di intervalli interi sono 2..5 per i numeri da 2 a 5 e 100..200 per i numeri da 100 a 200.

In modo simile a come chiamare println(), dice al sistema di stampare il testo specificato, puoi usare una funzione chiamata random() per generare e restituire un numero casuale per un determinato intervallo. Come in precedenza, puoi archiviare il risultato in una variabile.

  1. All'interno di main(), definisci una variabile denominata val, chiamata randomNumber.
  2. Fai in modo che randomNumber abbia il valore del risultato della chiamata all'intervallo random() nell'intervallo diceRange, come mostrato di seguito.
 val randomNumber = diceRange.random()

Stai chiamando random() su diceRange utilizzando un punto, o un punto, tra la variabile e la chiamata funzione. Puoi leggere questo testo come "generando un numero casuale da diceRange". Il risultato viene quindi memorizzato nella variabile randomNumber.

  1. Per vedere un numero generato in modo casuale, utilizza la notazione di formattazione della stringa (chiamata anche "modello di stringa" ${randomNumber}) per stamparla, come mostrato di seguito.
println("Random number: ${randomNumber}")

Il codice completato dovrebbe avere questo aspetto.

fun main() {
    val diceRange = 1..6
    val randomNumber = diceRange.random()
    println("Random number: ${randomNumber}")
}
  1. Esegui il codice più volte. Ogni volta dovresti vedere l'output come mostrato di seguito, con numeri casuali diversi.
Random number: 4

Quando tiri il dado, sono oggetti reali nelle tue mani. Anche se il codice che hai scritto funziona perfettamente, è difficile immaginarlo come un vero dado. Organizzare un programma in modo che sia più simile a ciò che rappresenta lo rende più facile da capire. Quindi, sarebbe fantastico avere dei dadi programmatici che puoi lanciare!

Tutti i dadi funzionano allo stesso modo. Hanno le stesse proprietà, ad esempio i lati, e hanno lo stesso comportamento, ovvero che possono essere ruotati. In Kotlin puoi creare un progetto programmatico di un dado che dice di avere dei lati e che può ottenere un numero casuale. Questo progetto è detto classe.

Da questa classe puoi quindi creare oggetti "dadi" effettivi, chiamati istanze di oggetti. Ad esempio, puoi creare un dado a 12 o 4 lati.

Definisci una classe di dadi

Nei passaggi seguenti, definirai una nuova classe denominata Dice, per rappresentare un dado che puoi rotolare.

  1. Per ricominciare da zero, cancella il codice nella funzione main() in modo da ottenere il codice come mostrato di seguito.
fun main() {

}
  1. Sotto questa funzione main(), aggiungi una riga vuota e aggiungi il codice per creare la classe Dice. Come mostrato di seguito, inizia con la parola chiave class, seguita dal nome della classe, seguito da una parentesi graffa di apertura e chiusura. Lascia spazio tra le parentesi graffe per inserire il codice per la classe.
class Dice {

}

All'interno della definizione di una classe, puoi specificare una o più proprietà per la classe utilizzando le variabili. I veri dadi possono avere diversi lati, un colore o un peso. In questa attività, ti concentrerai sulla proprietà del numero di lati del dado.

  1. All'interno della classe Dice, aggiungi un var chiamato sides per il numero di lati dei tuoi dadi. Imposta sides su 6.
class Dice {
    var sides = 6
}

Questo è tutto. Ora hai un corso molto semplice che rappresenta i dadi.

Crea un'istanza della classe Dice

Con questa lezione Dice, hai un modello di che cosa è detto un dado. Per avere un dado reale nel tuo programma, devi creare un'istanza di oggetto Dice. E se avessi bisogno di tre dadi, dovresti creare tre istanze di oggetto.

  1. Per creare un'istanza di oggetto Dice, nella funzione main(), crea un val chiamato myFirstDice e inizializzalo come istanza della classe Dice. Osserva le parentesi dopo il nome della classe, per indicare che stai creando una nuova istanza di oggetto dalla classe.
fun main() {
    val myFirstDice = Dice()
}

Ora che disponi di un oggetto myFirstDice, un elemento realizzato a partire dal progetto base, puoi accedere alle relative proprietà. L'unica proprietà di Dice è il suo sides. Accedi a una proprietà utilizzando la "notazione dei punti". Quindi, per accedere alla proprietà sides di myFirstDice, chiami myFirstDice.sides che viene pronunciata "myFirstDice punto sides".

  1. Sotto la dichiarazione di myFirstDice, aggiungi un'istruzione println() per generare il numero di sides di myFirstDice.
println(myFirstDice.sides)

Il tuo codice sarà simile al seguente:

fun main() {
    val myFirstDice = Dice()
    println(myFirstDice.sides)
}

class Dice {
    var sides = 6
}
  1. Esegui il tuo programma, che dovrebbe restituire il numero di sides definito nella classe Dice.
6

Ora hai una classe Dice e un dado reale myFirstDice con 6 sides.

Facciamo il dado!

Lancia i dadi

In precedenza hai utilizzato una funzione per eseguire l'azione di stampa degli strati di torta. Puoi anche eseguire il tiro dei dadi come funzione che può essere implementata in funzione. Dato che tutti i dadi possono essere lanciati, puoi aggiungere una funzione all'interno della classe Dice. Una funzione definita all'interno di una classe è chiamata anche metodo.

  1. Nella classe Dice, sotto la variabile sides, inserisci una riga vuota e crea una nuova funzione per lanciare i dadi. Inizia con la parola chiave Kotlin fun, seguita dal nome del metodo, seguito dalle parentesi () e infine dalle parentesi graffe di apertura e chiusura {}. Puoi lasciare una riga vuota tra le parentesi graffe per liberare spazio, come mostrato di seguito. Il tuo corso dovrebbe avere questo aspetto.
class Dice {
    var sides = 6

    fun roll() {

    }
}

Quando lancia un dado a sei facce, produce un numero casuale compreso tra 1 e 6.

  1. Nel metodo roll(), crea un val randomNumber. Assegnagli un numero casuale compreso nell'intervallo 1..6. Utilizza la notazione del punto per chiamare random() sull'intervallo.
val randomNumber = (1..6).random()
  1. Dopo aver generato il numero casuale, stampalo dalla console. Il metodo roll() che hai completato dovrebbe essere simile al seguente codice.
fun roll() {
     val randomNumber = (1..6).random()
     println(randomNumber)
}
  1. Per generare effettivamente myFirstDice, in main(), chiama il metodo roll() su myFirstDice. Viene chiamato un metodo utilizzando la "notazione dei punti". Pertanto, per chiamare il metodo roll() di myFirstDice, digita myFirstDice.roll(), che viene pronunciato "myFirstDice" roll()".
myFirstDice.roll()

Il codice completato avrà il seguente aspetto.

fun main() {
    val myFirstDice = Dice()
    println(myFirstDice.sides)
    myFirstDice.roll()
}

class Dice {
    var sides = 6

    fun roll() {
        val randomNumber = (1..6).random()
        println(randomNumber)
    }
}
  1. Esegui il codice. Dovresti vedere il risultato di un tiro di dadi casuale sotto il numero di lati. Esegui il codice più volte e nota che il numero di lati rimane lo stesso e il valore del tiro di dado cambia.
6
4

Complimenti! Hai definito una classe Dice con una variabile sides e una funzione roll(). Nella funzione main(), hai creato una nuova istanza di oggetto Dice e hai chiamato il metodo roll() per produrre un numero casuale.

Al momento stai stampando il valore di randomNumber nella tua funzione roll() e questo è un ottimo risultato. A volte, tuttavia, è più utile restituire il risultato di una funzione a quella chiamata funzione. Ad esempio, potresti assegnare il risultato del metodo roll() a una variabile e quindi spostare un giocatore di quella quantità. Vediamo come va.

  1. In main() modifica la riga myFirstDice.roll(). Crea un val chiamato diceRoll. Impostalo sul valore restituito dal metodo roll().
val diceRoll = myFirstDice.roll()

Questo non fa ancora nulla, perché roll() non restituisce ancora nulla. Affinché questo codice funzioni come previsto, roll() deve restituire qualcosa.

Nei codelab precedenti hai imparato che devi specificare un tipo di dati per le funzioni di input per le funzioni. Nello stesso modo, devi specificare un tipo di dati per i dati restituiti da una funzione.

  1. Modifica la funzione roll() per specificare il tipo di dati che verrà restituito. In questo caso, il numero casuale è Int, quindi il tipo di reso è Int. La sintassi per specificare il tipo di ritorno è: dopo il nome della funzione, dopo le parentesi, aggiungi i due punti, uno spazio e la parola chiave Int per il tipo di ritorno della funzione. La definizione della funzione dovrebbe essere simile al seguente codice.
fun roll(): Int {
  1. Esegui questo codice. Verrà visualizzato un errore nella Visualizzazione dei problemi. Dice:
A ‘return'  expression is required in a function with a block body. 

Hai modificato la definizione della funzione per restituire un elemento Int, ma il sistema si lamenta del fatto che

il codice non restituisce alcun Int. "Blocca corpo" o "corpo funzione" si riferisce al codice tra parentesi graffe di una funzione. Puoi correggere questo errore restituendo un valore da una funzione utilizzando un'istruzione return alla fine del corpo della funzione.

  1. In roll(), rimuovi l'istruzione println() e sostituiscila con un'istruzione return per randomNumber. La funzione roll() dovrebbe essere simile al seguente codice.
fun roll(): Int {
     val randomNumber = (1..6).random()
     return randomNumber
}
  1. In main() rimuovi l'istruzione di stampa per i lati del dado.
  2. Aggiungi un'istruzione per stampare il valore di sides e diceRoll in una frase informativa. La funzione main() completata dovrebbe essere simile al codice riportato di seguito.
fun main() {
    val myFirstDice = Dice()
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
}
  1. Esegui il codice e l'output dovrebbe essere simile al seguente.
Your 6 sided dice rolled 4!

Ecco tutto il codice finora.

fun main() {
    val myFirstDice = Dice()
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
}


class Dice {
    var sides = 6

    fun roll(): Int {
        val randomNumber = (1..6).random()
        return randomNumber
    }
}

Non tutti i dadi hanno 6 lati! I dadi sono disponibili in tutte le forme e dimensioni: 4 lati, 8 lati, fino a 120 lati!

  1. Nella tua classe Dice, nel metodo roll(), modifica l'elemento 1..6 hardcoded per utilizzare sides in modo che l'intervallo, e quindi il numero casuale eseguito, siano sempre corretti per il numero di lati.
val randomNumber = (1..sides).random()
  1. Nella funzione main(), sotto e dopo aver stampato il lancio dei dadi, imposta sides del mio FirstDice su 20.
myFirstDice.sides = 20
  1. Copia e incolla l'estratto conto esistente di seguito dopo aver modificato il numero di lati.
  2. Sostituisci la stampa di diceRoll con la stampa del risultato della chiamata del metodo roll() su myFirstDice.
println("Your ${myFirstDice.sides} sided dice has rolled a ${myFirstDice.roll()}!")

Il tuo programma dovrebbe avere un aspetto simile a questo.

fun main() {
   
    val myFirstDice = Dice()
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")

    myFirstDice.sides = 20
    println("Your ${myFirstDice.sides} sided dice rolled ${myFirstDice.roll()}!")
}

class Dice {
    var sides = 6

    fun roll(): Int {
        val randomNumber = (1..sides).random()
        return randomNumber
    }
}
  1. Esegui il programma e dovresti visualizzare un messaggio per il dado a 6 facce.
Your 6 sided dice rolled 3!
Your 20 sided dice rolled 15!

L'idea di una classe è rappresentare una cosa, spesso fisica nel mondo reale. In questo caso, un corso Dice rappresenta un dado fisico. Nel mondo reale, i dadi non possono cambiare il numero di lati. Se vuoi un numero diverso di lati, devi ottenere un dado diverso. A livello di programmazione, ciò significa che anziché modificare la proprietà dei lati di un'istanza di oggetto Dice esistente, devi creare una nuova istanza di oggetto dadi con il numero di lati necessari.

In questa attività modificherai la classe Dice in modo da poter specificare il numero di lati quando crei una nuova istanza. Modifica la definizione della classe Dice per accettare un argomento per il numero di lati. Questo metodo è simile all'accettazione di argomenti da parte di una funzione.

  1. Modifica la definizione della classe Dice per accettare un argomento intero chiamato numSides. Il codice all'interno del corso non cambia.
class Dice(val numSides: Int) {
   // Code inside does not change.
}
  1. All'interno della classe Dice, elimina la variabile sides, poiché ora puoi utilizzare numSides.
  2. Inoltre, correggi l'intervallo per utilizzare numSides.

Il tuo corso Dice dovrebbe avere un aspetto simile a questo.

class Dice (val numSides: Int) {

    fun roll(): Int {
        val randomNumber = (1..numSides).random()
        return randomNumber
    }
}

Se esegui questo codice, verranno visualizzati molti errori perché devi aggiornare main() in modo che funzioni con le modifiche apportate alla classe Dice.

  1. In main(), per creare myFirstDice con 6 lati, ora devi passare il numero di lati come argomento alla classe Dice, come mostrato di seguito.
    val myFirstDice = Dice(6)
  1. Nell'estratto conto cartaceo, modifica sides in numSides.
  2. Elimina immediatamente il codice che sostituisce sides con 20, perché la variabile non esiste più.
  3. Elimina anche l'istruzione println sottostante.

La funzione main() dovrebbe essere simile al seguente codice e, se viene eseguita, non dovrebbero verificarsi errori.

fun main() {
    val myFirstDice = Dice(6)
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
}
  1. Dopo aver stampato il primo lancio di dadi, aggiungi il codice per creare e stampare un secondo oggetto Dice chiamato mySecondDice con 20 lati.
    val mySecondDice = Dice(20)
  1. Aggiungi un'istruzione di stampa che esegua il rollback e stampa il valore restituito.
println("Your ${mySecondDice.numSides} sided dice rolled  ${mySecondDice.roll()}!")
  1. La funzione main() completata dovrebbe essere simile a questa.
fun main() {
    val myFirstDice = Dice(6)
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
    
    val mySecondDice = Dice(20)
    println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}

class Dice (val numSides: Int) {

    fun roll(): Int {
        val randomNumber = (1..numSides).random()
        return randomNumber
    }
}
  1. Esegui il programma finito e l'output dovrebbe avere il seguente aspetto.
Your 6 sided dice rolled 5!
Your 20 sided dice rolled 7!

Quando scrivi il codice, è conciso. Puoi eliminare la variabile randomNumber e restituire direttamente il numero casuale.

  1. Modifica l'istruzione return in modo che restituisca direttamente il numero casuale.
    fun roll(): Int {
        return (1..numSides).random()
    }

Nella seconda istruzione di stampa, chiama la chiamata per ottenere il numero casuale nel modello di stringa. Per eliminare la variabile diceRoll, devi eseguire la stessa operazione nella prima istruzione di stampa.

  1. Chiama myFirstDice.roll() nel modello di stringa ed elimina la variabile diceRoll. Le prime due righe del codice main() hanno ora il seguente aspetto.
    val myFirstDice = Dice(6)
    println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
  1. Esegui il codice e l'output non dovrebbe differire.

Questo è il tuo codice finale dopo il refactoring .

fun main() {
    val myFirstDice = Dice(6)
    println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
    
    val mySecondDice = Dice(20)
    println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}

class Dice (val numSides: Int) {

    fun roll(): Int {
        return (1..numSides).random()
    }
}
fun main() {
    val myFirstDice = Dice(6)
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
    
    val mySecondDice = Dice(20)
    println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}

class Dice (val numSides: Int) {

    fun roll(): Int {
        return (1..numSides).random()
    }
}
  • Chiama la funzione random() su un IntRange per generare un numero casuale: (1..6).random()
  • Le classi sono come un modello di un oggetto. Possono avere proprietà e comportamenti implementati come variabili e funzioni.
  • Un'istanza di una classe rappresenta un oggetto, spesso un oggetto fisico, ad esempio un dado. Puoi chiamare le azioni sull'oggetto e modificarne gli attributi.
  • Puoi passare l'input a una classe quando crei un'istanza specificando un argomento per la definizione della classe. Ad esempio: class Dice(val numSides: Int), quindi crea un'istanza con Dice(6).
  • Le funzioni possono restituire qualcosa. Specifica il tipo di dati da restituire nella definizione della funzione e utilizza un'istruzione return nel corpo della funzione per restituire l'elemento. Ad esempio: fun example(): Int { return 5 }.

Segui questi passaggi:

  • Dai alla tua classe Dice un altro attributo di colore e crea più istanze di dadi usando diversi lati e colori.
  • Crea una classe Coin, dai la possibilità di girare, creare un'istanza della classe e girare alcune monete! Come utilizzeresti la funzione casual() con un intervallo per realizzare il lancio della moneta?