1. Oggetti e classi

Oggi imparerai qualcosa su come funziona un tipico programma Java. Ecco la grande novità: ogni programma Java è costituito da classi e oggetti.

Sai già cosa sono le classi, ma cosa sono gli oggetti?

Inizierò con un'analogia. Immagina di voler costruire una piccola nave. Per prima cosa devi creare un progetto e poi consegnarlo alla fabbrica, dove verrà costruita una nave secondo il progetto. O forse una dozzina. O quante navi vuoi. Dozzine di navi identiche sono costruite secondo un unico progetto. Questa è la cosa importante qui.

È lo stesso nella programmazione Java.

Cianografie

Un programmatore è come un designer. Un designer crea progetti e un programmatore Java scrive classi. Le parti vengono create in base ai progetti e gli oggetti vengono creati in base alle classi.

Per prima cosa, scriviamo classi (creiamo progetti) e poi, mentre il programma viene eseguito, la macchina Java crea oggetti basati su queste classi. Allo stesso modo in cui le navi vengono create dai progetti.

C'è solo un progetto, ma possono esserci molte navi. Le navi sono distinte: hanno nomi diversi e trasportano carichi diversi. Ma sono molto simili: condividono tutti lo stesso design e possono svolgere compiti simili.

Oppure ecco un'altra analogia...

Formicaio

Un formicaio è un buon esempio di come interagiscono gli oggetti. Ci sono tre classi di formiche in un semplice formicaio: la regina, i soldati e gli operai.

Il numero di formiche di ogni classe è diverso. C'è una sola regina per l'intero formicaio, ma ci sono dozzine di soldati e centinaia di formiche operaie. Tre classi e centinaia di oggetti. Le formiche interagiscono tra loro - con formiche della loro stessa classe e con formiche di altre classi - secondo rigide regole.

Questo è l'esempio perfetto. Tutto è esattamente così in un programma tipico. C'è un oggetto primario che crea oggetti di tutte le altre classi. Gli oggetti iniziano a interagire tra loro e con il "mondo esterno" del programma. Il comportamento degli oggetti è codificato internamente.

Queste due analogie sono due facce della stessa medaglia. La verità sta nel mezzo. Il primo esempio (su un progetto e le navi) mostra la relazione tra una classe e gli oggetti di quella classe. Questa è una forte analogia. Il secondo esempio (su un formicaio) mostra la relazione tra le classi scritte e gli oggetti che esistono durante l'esecuzione del programma.

Devi prima scrivere classi per ogni oggetto che esisterà nel programma, e poi descrivere anche come interagiscono. Sì, è vero, ma è più facile di quanto sembri.

In Java, tutte le entità sono oggetti in fase di esecuzione e scrivere un programma significa descrivere i diversi modi in cui gli oggetti interagiscono. Gli oggetti chiamano semplicemente i metodi l'uno dell'altro e passano loro i dati richiesti.

Documentazione

E come fai a sapere quali dati passare ai metodi? Le persone che sono venute prima di te hanno pensato a tutto.

Ogni classe ha in genere una descrizione che dice per cosa è stata creata. Inoltre, ogni metodo pubblico di solito ha una descrizione che indica cosa fa e quali dati gli devono essere passati.

Per usare una classe, devi avere un'idea generale di cosa fa. E devi sapere esattamente cosa fa ogni metodo. Ma non hai affatto bisogno di sapere come lo fa. È come una bacchetta magica.

Diamo un'occhiata al codice per copiare un file:

Copia del file c:\\data.txt nel file c:\\result.txt
package com.codegym.lesson2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopy
{
   public static void main(String[] args) throws IOException
   {
      FileInputStream fileInputStream = new FileInputStream("c:\\data.txt");
      FileOutputStream fileOutputStream = new FileOutputStream("c:\\result.txt");

      while (fileInputStream.available() > 0)
      {
         int data = fileInputStream.read();
         fileOutputStream.write(data);
      }

      fileInputStream.close();
      fileOutputStream.close();
   }
}

Se leggi questo codice riga per riga, puoi indovinare cosa fa in termini generali. Anche se ciò richiede esperienza e pratica. Dopo un po' questo codice vi sembrerà familiare e comprensibile.


2. Progettazione di un programma

Il design del programma è un'intera arte. È allo stesso tempo semplice e difficile. Semplice, perché non ci sono leggi ferree: tutto ciò che non è proibito è permesso. Bene, ed è anche questo che rende difficile: ci sono molti modi per fare qualcosa e non è facile trovare quello migliore.

Progettare un programma è come scrivere un libro. Da un lato, scrivi solo lettere, parole e frasi. D'altra parte, sono importanti la trama, i personaggi, le contraddizioni interne, i conflitti, lo stile narrativo, gli intrighi, ecc.

La cosa principale è capire per chi stai scrivendo il codice. E scrivi codice per altri programmatori .

Lo sviluppo del prodotto comporta inevitabilmente modifiche: qualcosa viene aggiunto qui, qualcos'altro viene rimosso lì, qualcosa viene ridisegnato. È così che da piccole iterazioni nascono progetti grandi, enormi e giganteschi.

Ciò che conta di più per il codice è che deve essere comprensibile per altri programmatori. Il codice errato comprensibile può essere corretto. Il codice corretto ma incomprensibile non può essere migliorato.  Tutto quello che puoi fare è scartarlo.

Quindi, come si scrive un codice buono e pulito?

Fare questo richiede tre cose:

  • Scrivere codice valido e comprensibile all'interno dei metodi: questo è il requisito più semplice
  • Decidere quali entità dovrebbero essere incluse nel programma
  • Suddividere correttamente il programma in parti logiche

Cosa c'è dietro questi concetti?

Scrivere un buon codice all'interno dei metodi

Se hai anche competenze di base in inglese, potresti aver notato quanto può essere facile leggere il codice come frasi inglesi a volte:

  • class Cat extends Pet— Ciò significa che la classe Cat estende la classe Pet
  • while(stream.ready())- fintanto che il flusso è pronto...
  • if (a<b) return a; else return b— se aè minore di b, allora return a, altrimenti return b.

Questo è deliberato. Java è uno dei tanti linguaggi che rendono facile scrivere codice auto-documentante, cioè codice comprensibile senza commenti. In un buon codice Java, molti metodi si leggono proprio come frasi inglesi.

Quando scrivi il codice, il tuo compito è renderlo il più semplice e conciso possibile. Pensa solo se il tuo codice è facile da leggere e inizierai a muoverti nella giusta direzione.

In Java, è consuetudine scrivere codice facile da leggere. Preferibilmente, tutto il codice di un metodo starà su un'unica schermata (cioè 20-30 righe). Questa è la norma per l'intera comunità Java. Se il codice può essere migliorato, dovrebbe essere migliorato.

Il modo migliore per imparare a scrivere un buon codice è attraverso la pratica. Scrivi molto codice, studia il codice degli altri e chiedi ai colleghi più esperti di rivedere il tuo codice.

E ricorda che nel momento in cui ti dici "lascia stare abbastanza bene", la tua crescita si ferma.

Decidere quali entità dovrebbero essere incluse nel programma

Devi scrivere codice che altri programmatori possano capire. Se 9 programmatori su 10 includessero le classi A, B e C nella progettazione di un programma, allora dovresti creare anche le classi A, B e C nel tuo programma. Devi scrivere codice che gli altri possano capire.

Ottimo, funzionante, veloce, ma il codice non standard è un codice errato.

Devi studiare i progetti di altre persone: questo è il modo migliore, più veloce e più semplice per assorbire tutta la saggezza che si è accumulata nel settore IT per decenni.

E a proposito, hai già accesso a un progetto eccellente, popolare e ben documentato: Java SDK . Inizia con esso.

Analizza le classi e come sono organizzate. Pensa al motivo per cui alcuni metodi sono statici e altri no. Perché i metodi hanno i parametri specifici che hanno ma non altri. Perché questi metodi esattamente, e perché le classi sono chiamate come sono chiamate e perché sono contenute nei loro pacchetti specifici.

Una volta che inizi a comprendere le risposte a tutte queste domande, sarai in grado di scrivere codice comprensibile agli altri.

Detto questo, voglio metterti in guardia contro l'analisi del codice nei metodi dell'SDK Java. Molti dei metodi sono stati riscritti per massimizzare la velocità e la loro leggibilità è discutibile.

Suddividere correttamente il programma in parti logiche

Quasi ogni programma è diviso in parti o moduli. Ogni parte è responsabile del proprio aspetto del programma.

Un computer ha una scheda madre, un monitor e una tastiera: sono tutte parti separate e accoppiate in modo lasco. Inoltre, interagiscono in modi standardizzati: USB, HDMI, ecc. Se versi del caffè sulla tastiera, puoi semplicemente lavarlo via nel lavandino, lasciarlo asciugare e continuare a usarlo.

Ma un laptop è un esempio di architettura monolitica: sembra che possiamo distinguere parti logiche separate, ma sono molto più integrate. Su un MacBookPro, devi smontare metà del laptop per pulire la tastiera. E versare il caffè su un laptop è un motivo per ordinare un nuovo laptop. Non una nuova tazza di caffè.


3. Creare le proprie classi

Ma dal momento che stai solo imparando a programmare, dovresti iniziare in piccolo imparando a creare le tue classi.

Certo, hai già creato classi, ma devi imparare a capire quali classi dovrebbero essere incluse in un programma, come dovrebbero essere denominate e quali metodi dovrebbero avere. E come dovrebbero interagire tra loro.

Elenco delle entità

Se non sai da dove iniziare, inizia dall'inizio.

Quando inizi a progettare un programma per la prima volta, puoi semplicemente prendere un pezzo di carta e scrivere un elenco delle entità (oggetti) che dovrebbero essere nel programma. E poi scrivi il codice secondo il principio che ogni entità è una classe separata.

Esempio

Diciamo che vuoi scrivere una partita a scacchi. Avrai bisogno delle seguenti entità: una scacchiera e 6 tipi di pezzi degli scacchi. I pezzi si muovono in modi diversi e hanno valori diversi. Ha senso che siano classi separate. In effetti, quando inizi per la prima volta, più lezioni ci sono, meglio è.

È molto raro incontrare un programmatore alle prime armi che scrive dieci classi invece di due. Invece di scrivere dieci lezioni, i principianti adorano scrivere due lezioni o forse solo una. Quindi, per favore, scrivi più classi, miei colleghi programmatori. E il tuo codice diventerà più chiaro a tutti tranne forse a te 😛

Scacchi

Supponiamo di decidere di scrivere classi per gli scacchi: come sarebbero queste classi?

La scacchiera è solo un array 8 per 8? È meglio creare una classe separata che memorizzi internamente un riferimento a un array. Quindi puoi aggiungere molti metodi utili alla classe "scacchiera", ad esempio, per verificare se una cella specifica è vuota o occupata

In generale, quando inizi, fatti sempre guidare da questo principio: un programma ha varie entità e un'entità ha un tipo. Questo tipo è la classe.


4. Variabili statiche e metodi

Inoltre, non dimenticare di utilizzare variabili e metodi statici. Se hai un pezzo degli scacchi che interagisce con un altro sulla scacchiera, allora il tuo codice ha bisogno di un metodo che prenda riferimenti al primo e al secondo pezzo così come alla scacchiera.

Le variabili statiche, a cui è possibile accedere da qualsiasi punto del programma, vengono generalmente utilizzate per evitare di passare costantemente riferimenti a oggetti che "esistono sempre".

Ad esempio, in questo modo:

Codice Nota
public class ChessBoard
{
   public static ChessBoard board = new ChessBoard();
   public ChessItem[][] cells = new ChessItem[8][8];
   ...
}

public class Game
{
   public static void main(String[] args)
   {
      var board = ChessBoard.board;
      board.cells[0][3] = new King(Color.WHITE);
      board.cells[0][4] = new Queen(Color.WHITE);
      ...
   }
}


Un riferimento a un singolo ChessBoardoggetto.
Un array bidimensionale 8x8, non una variabile statica.








Aggiungi i pezzi alla scacchiera.

Oppure, invece di una variabile statica, puoi creare un metodo che restituisca un oggetto singleton. Ad esempio, in questo modo:

public class ChessBoard
{
   private static ChessBoard board = new ChessBoard();
   public static ChessBoard getBoard()
   {
      return board;
   }

   public ChessItem[][] cells = new ChessItem[8][8];
   ...
}

public class Game
{
   public static void main(String[] args)
   {
      var board = ChessBoard.getBoard();
      board.cells[0][3] = new King(Color.WHITE);
      board.cells[0][4] = new Queen(Color.WHITE);
      ...
   }
}