1. Obiecte și clase

Astăzi veți afla puțin despre cum funcționează un program tipic Java. Iată vestea cea mare: fiecare program Java este format din clase și obiecte.

Știi deja ce sunt clasele, dar ce sunt obiectele?

Voi începe cu o analogie. Imaginează-ți că vrei să faci o navă mică. Mai întâi trebuie să creați un plan și apoi să îl oferiți fabricii, unde va fi construită o navă conform planului. Sau poate zeci. Sau câte nave vrei. Zeci de nave identice sunt construite conform unui singur plan. Acesta este lucrul important aici.

La fel este și în programarea Java.

Planuri

Un programator este ca un designer. Un designer creează planuri, iar un programator Java scrie clase. Părțile sunt create pe baza planurilor, iar obiectele sunt create pe baza claselor.

Mai întâi, scriem clase (facem planuri), iar apoi, pe măsură ce programul rulează, mașina Java creează obiecte pe baza acestor clase. În același mod în care navele sunt create din planuri.

Există un singur plan, dar pot fi multe nave. Navele sunt distincte - au nume diferite și transportă mărfuri diferite. Dar sunt foarte asemănătoare: toate au același design și pot îndeplini sarcini similare.

Sau iată o altă analogie...

Musuroi de furnici

Un furnicar este un bun exemplu al modului în care obiectele interacționează. Există trei clase de furnici într-un furnicar simplu: regina, soldații și muncitorii.

Numărul de furnici din fiecare clasă este diferit. Există o singură regină pentru întreg furnicarul, dar există zeci de soldați și sute de furnici muncitoare. Trei clase și sute de obiecte. Furnicile interacționează între ele - cu furnici din aceeași clasă și cu furnici din alte clase - conform unor reguli rigide.

Acesta este exemplul perfect. Totul este exact așa într-un program tipic. Există un obiect primar care creează obiecte din toate celelalte clase. Obiectele încep să interacționeze între ele și cu „lumea exterioară” a programului. Comportamentul obiectelor este codificat intern.

Aceste două analogii sunt două fețe ale aceleiași monede. Adevărul este la mijloc. Primul exemplu (despre un plan și nave) arată relația dintre o clasă și obiectele acelei clase. Aceasta este o analogie puternică. Al doilea exemplu (despre un furnicar) arată relația dintre clasele scrise și obiectele care există pe măsură ce programul rulează.

Mai întâi trebuie să scrieți clase pentru fiecare obiect care va exista în program și apoi să descrieți și modul în care interacționează. Da, așa este, dar este mai ușor decât pare.

În Java, toate entitățile sunt obiecte în timpul execuției, iar scrierea unui program înseamnă descrierea diferitelor moduri în care obiectele interacționează. Obiectele pur și simplu își apelează metodele unul altuia și le transmit datele necesare.

Documentație

Și de unde știi ce date să treci la metode? Oamenii care au venit înaintea ta s-au gândit la toate.

Fiecare clasă are de obicei o descriere care spune pentru ce a fost creată. De asemenea, fiecare metodă publică are de obicei o descriere care indică ceea ce face și ce date trebuie să i se transmită.

Pentru a folosi o clasă, trebuie să aveți o idee generală despre ceea ce face. Și trebuie să știi exact ce face fiecare metodă. Dar nu trebuie deloc să știi cum se face. Este ca o baghetă magică.

Să aruncăm o privire la codul pentru copierea unui fișier:

Copierea fișierului c:\\data.txt în fișierul 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();
   }
}

Dacă citiți acest cod linie cu linie, puteți ghici ce face în termeni generali. Deși pentru asta necesită experiență și practică. După un timp, acest cod vă va părea familiar și de înțeles.


2. Proiectarea unui program

Proiectarea programului este o întreagă artă. Este în același timp simplu și dificil. Simplu, pentru că nu există legi stricte: tot ceea ce nu este interzis este permis. Ei bine, și asta este și ceea ce face dificilă: există o mulțime de moduri de a face ceva și nu este ușor să o găsești pe cea mai bună.

Proiectarea unui program este ca și cum ai scrie o carte. Pe de o parte, scrii doar litere, cuvinte și propoziții. Pe de altă parte, sunt importante intriga, personajele, contradicțiile interne, conflictele, stilul de povestire, intriga etc.

Principalul lucru este să înțelegeți pentru cine scrieți codul. Și scrii cod pentru alți programatori .

Dezvoltarea unui produs înseamnă inevitabil efectuarea de schimbări: ceva se adaugă aici, altceva se elimină acolo, ceva este reproiectat. Așa se nasc proiecte mari, enorme și gigantice din mici iterații.

Ceea ce contează cel mai mult pentru cod este că trebuie să fie înțeles de alți programatori. Codul incorect care este de înțeles poate fi corectat. Codul corect, dar de neînțeles, nu poate fi îmbunătățit.  Tot ce poți face este să-l arunci.

Deci, cum scrieți cod bun și curat?

Pentru a face acest lucru necesită trei lucruri:

  • Scrierea unui cod bun și ușor de înțeles în cadrul metodelor - aceasta este cea mai ușoară cerință
  • Decizia ce entități ar trebui incluse în program
  • Împărțirea corectă a programului în părți logice

Ce se află în spatele acestor concepte?

Scrierea unui cod bun în cadrul metodelor

Dacă aveți chiar și abilități de bază în limba engleză, este posibil să fi observat cât de ușor poate fi să citiți codul ca propoziții în engleză uneori:

  • class Cat extends Pet— Aceasta înseamnă că clasa Cat extinde clasa Pet
  • while(stream.ready())- atâta timp cât fluxul este gata...
  • if (a<b) return a; else return b— dacă aeste mai mic decât b, atunci returnează a, în caz contrar returnează b.

Acest lucru este deliberat. Java este unul dintre mai multe limbaje care facilitează scrierea codului auto-documentat, adică cod care este de înțeles fără comentarii. În codul Java bun, multe metode citesc la fel ca propozițiile în engleză.

Când scrieți cod, sarcina dvs. este să îl faceți cât mai simplu și concis posibil. Gândește-te doar dacă codul tău este ușor de citit și vei începe să mergi în direcția corectă.

În Java, este obișnuit să scrieți cod ușor de citit. De preferință, tot codul pentru o metodă se va potrivi pe un singur ecran (adică 20-30 de linii). Aceasta este norma pentru întreaga comunitate Java. Dacă codul poate fi îmbunătățit, ar trebui să fie îmbunătățit.

Cel mai bun mod de a învăța cum să scrieți cod bun este prin practică. Scrieți mult cod, studiați codul altora și cereți colegilor mai experimentați să vă revizuiască codul.

Și amintește-ți că în momentul în care îți spui „lasă destul de bine în pace”, creșterea ta se oprește.

Decizia ce entități ar trebui incluse în program

Trebuie să scrieți cod pe care alți programatori îl pot înțelege. Dacă 9 din 10 programatori ar include clasele A, B și C în designul unui program, atunci ar trebui să creați și clasele A, B și C în programul dvs. Trebuie să scrieți un cod pe care alții îl pot înțelege.

Grozav, funcțional, rapid, dar codul non-standard este un cod prost.

Trebuie să studiezi proiectele altora: acesta este cel mai bun, cel mai rapid și cel mai simplu mod de a absorbi toată înțelepciunea acumulată în industria IT de zeci de ani.

Și, apropo, aveți deja acces la un proiect excelent, popular și bine documentat - Java SDK . Începe cu el.

Analizați orele și modul în care sunt organizate. Gândiți-vă de ce unele metode sunt statice, iar altele nu. De ce metodele au parametrii specifici pe care le au, dar nu altele. De ce exact aceste metode și de ce clasele sunt numite așa cum sunt numite și de ce sunt conținute în pachetele lor specifice.

Odată ce începeți să înțelegeți răspunsurile la toate aceste întrebări, veți putea scrie cod pe care alții îl pot înțelege.

Acestea fiind spuse, vreau să vă avertizez să nu analizați codul în metodele SDK-ului Java. Multe dintre metode au fost rescrise pentru a maximiza viteza, iar lizibilitatea lor este discutabilă.

Împărțirea corectă a programului în părți logice

Aproape fiecare program este împărțit în părți sau module. Fiecare parte este responsabilă pentru propriul aspect al programului.

Un computer are o placă de bază, un monitor și tastatură - toate acestea sunt părți separate, cuplate liber. În plus, ele interacționează în moduri standardizate: USB, HDMI etc. Dacă vărsați cafea pe tastatură, puteți pur și simplu să o spălați în chiuvetă, să o lăsați să se usuce și apoi să continuați să o utilizați.

Dar un laptop este un exemplu de arhitectură monolitică: se pare că putem discerne părți logice separate, dar sunt mult mai integrate. Pe un MacBookPro, trebuie să dezasamblați jumătate din laptop pentru a curăța tastatura. Și vărsarea cafelei pe un laptop este un motiv pentru a comanda un laptop nou. Nu o ceașcă nouă de cafea.


3. Crearea propriilor clase

Dar, din moment ce doar înveți să programezi, ar trebui să începi puțin prin a învăța să-ți creezi propriile clase.

Desigur, ați creat deja clase, dar trebuie să învățați să înțelegeți ce clase ar trebui incluse într-un program, cum ar trebui să fie denumite și ce metode ar trebui să aibă. Și cum ar trebui să interacționeze între ei.

Lista entităților

Dacă nu știi de unde să începi, începe de la început.

Când începeți pentru prima dată să proiectați un program, puteți pur și simplu să luați o bucată de hârtie și să scrieți o listă cu entitățile (obiectele) care ar trebui să fie în program. Și apoi scrieți codul conform principiului că fiecare entitate este o clasă separată.

Exemplu

Să presupunem că vrei să scrii un joc de șah. Veți avea nevoie de următoarele entități: o tablă de șah și 6 tipuri de piese de șah. Piesele se mișcă în moduri diferite și au valori diferite. Are sens că sunt clase separate. Într-adevăr, când începi prima dată, cu cât mai multe cursuri, cu atât mai bine.

Este foarte rar să întâlnești un programator începător care scrie zece clase în loc de două. În loc să scrie zece clase, începătorilor le place să scrie două clase sau poate doar una. Așa că vă rog să scrieți mai multe cursuri, colegii mei programatori. Și codul tău va deveni mai clar pentru toată lumea, cu excepția, poate, pentru tine 😛

Şah

Să presupunem că decidem să scriem cursuri pentru șah: cum ar arăta aceste clase?

Tabla de șah este doar o matrice 8 pe 8? Este mai bine să creați o clasă separată care stochează intern o referință la o matrice. Apoi puteți adăuga o mulțime de metode utile la clasa „tabla de șah”, de exemplu, pentru a verifica dacă o anumită celulă este goală sau ocupată

În general, pe măsură ce începeți, ghidați-vă întotdeauna de acest principiu: un program are diverse entități, iar o entitate are un tip. Acest tip este clasa.


4. Variabile și metode statice

De asemenea, nu uitați să utilizați variabile și metode statice. Dacă aveți o piesă de șah care interacționează cu alta pe tabla de șah, atunci codul dvs. are nevoie de o metodă care să ia referințe la prima și a doua piesă, precum și la tabla de șah.

Variabilele statice, care pot fi accesate de oriunde în program, sunt utilizate de obicei pentru a evita trecerea constantă a referințelor la obiecte care „există întotdeauna”.

De exemplu, așa:

Cod Notă
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);
      ...
   }
}


O referire la un singur ChessBoardobiect.
O matrice bidimensională de 8x8, nu o variabilă statică.








Adăugați piesele pe tablă.

Sau în loc de o variabilă statică, puteți crea o metodă care returnează un obiect singleton. De exemplu, așa:

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);
      ...
   }
}