1. Objecten en klassen

Vandaag leer je iets over hoe een typisch Java-programma werkt. Dit is het grote nieuws: elk Java-programma bestaat uit klassen en objecten.

Je weet al wat klassen zijn, maar wat zijn objecten?

Ik begin met een analogie. Stel je voor dat je een klein schip wilt maken. Eerst moet je een blauwdruk maken en deze vervolgens aan de fabriek geven, waar volgens de blauwdruk een schip zal worden gebouwd. Of misschien wel tientallen. Of zoveel schepen als je wilt. Volgens één blauwdruk worden tientallen identieke schepen gebouwd. Dat is het belangrijkste hier.

Het is hetzelfde in Java-programmering.

Blauwdrukken

Een programmeur is als een ontwerper. Een ontwerper maakt blauwdrukken en een Java-programmeur schrijft klassen. Onderdelen worden gemaakt op basis van de blauwdrukken en objecten worden gemaakt op basis van klassen.

Eerst schrijven we klassen (maken blauwdrukken) en vervolgens, terwijl het programma wordt uitgevoerd, maakt de Java-machine objecten op basis van deze klassen. Op dezelfde manier dat schepen worden gemaakt op basis van blauwdrukken.

Er is maar één blauwdruk, maar er kunnen veel schepen zijn. De schepen zijn verschillend - ze hebben verschillende namen en vervoeren verschillende ladingen. Maar ze lijken erg op elkaar: ze hebben allemaal hetzelfde ontwerp en kunnen vergelijkbare taken uitvoeren.

Of hier is een andere analogie...

Mierenhoop

Een mierenhoop is een goed voorbeeld van hoe objecten op elkaar inwerken. Er zijn drie soorten mieren in een eenvoudige mierenhoop: de koningin, soldaten en arbeiders.

Het aantal mieren van elke klasse is anders. Er is één koningin voor de hele mierenhoop, maar er zijn tientallen soldaten en honderden werkmieren. Drie klassen en honderden objecten. Mieren communiceren met elkaar - met mieren van dezelfde klasse en met mieren van andere klassen - volgens strikte regels.

Dit is het perfecte voorbeeld. Alles is precies zo in een typisch programma. Er is een primair object dat objecten van alle andere klassen maakt. De objecten beginnen met elkaar en met de "buitenwereld" van het programma te interageren. Het gedrag van de objecten is intern hard gecodeerd.

Deze twee analogieën zijn twee kanten van dezelfde medaille. De waarheid ligt in het midden. Het eerste voorbeeld (over een blauwdruk en schepen) toont de relatie tussen een klasse en objecten van die klasse. Dit is een sterke analogie. Het tweede voorbeeld (over een mierenhoop) toont de relatie tussen de geschreven klassen en de objecten die bestaan ​​terwijl het programma draait.

U moet eerst klassen schrijven voor elk object dat in het programma zal bestaan, en dan ook beschrijven hoe ze op elkaar inwerken. Ja, dat klopt, maar het is makkelijker dan het klinkt.

In Java zijn alle entiteiten tijdens runtime objecten, en het schrijven van een programma gaat over het beschrijven van de verschillende manieren waarop objecten met elkaar omgaan. Objecten roepen gewoon elkaars methoden aan en geven de vereiste gegevens aan hen door.

Documentatie

En hoe weet u welke gegevens u aan methoden moet doorgeven? De mensen die je voorgingen, hebben aan alles gedacht.

Elke klasse heeft meestal een beschrijving die aangeeft waarvoor deze is gemaakt. Ook heeft elke openbare methode meestal een beschrijving die aangeeft wat deze doet en welke gegevens eraan moeten worden doorgegeven.

Om een ​​klasse te gebruiken, moet u een algemeen idee hebben van wat deze doet. En je moet precies weten wat elke methode doet. Maar je hoeft helemaal niet te weten hoe het dat doet. Het is als een toverstaf.

Laten we eens kijken naar de code voor het kopiëren van een bestand:

Het bestand c:\\data.txt naar het bestand c:\\result.txt kopiëren
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();
   }
}

Als u deze code regel voor regel leest, kunt u raden wat deze in algemene termen doet. Al vergt dat ervaring en oefening. Na een tijdje zal deze code u bekend en begrijpelijk voorkomen.


2. Een programma ontwerpen

Programmaontwerp is een hele kunst. Het is tegelijk eenvoudig en moeilijk. Simpel, want er zijn geen strikte wetten: alles wat niet verboden is mag. Tja, en dat maakt het ook zo moeilijk: er zijn veel manieren om iets te doen en het is niet makkelijk om de beste te vinden.

Een programma ontwerpen is als het schrijven van een boek. Aan de ene kant schrijf je gewoon letters, woorden en zinnen. Aan de andere kant zijn de plot, personages, interne tegenstellingen, conflicten, vertelstijl, intriges, enz. Belangrijk.

Het belangrijkste is om te begrijpen voor wie u de code schrijft. En je schrijft code voor andere programmeurs .

Productontwikkeling betekent onvermijdelijk veranderingen aanbrengen: hier wordt iets toegevoegd, daar iets anders verwijderd, iets opnieuw ontworpen. Zo ontstaan ​​grote, enorme en gigantische projecten uit kleine iteraties.

Het belangrijkste voor code is dat het begrijpelijk moet zijn voor andere programmeurs. Onjuiste code die begrijpelijk is, kan worden gecorrigeerd. Correcte maar onbegrijpelijke code kan niet worden verbeterd.  Het enige wat je kunt doen is het weggooien.

Dus hoe schrijf je goede, schone code?

Hiervoor zijn drie dingen nodig:

  • Het schrijven van goede en begrijpelijke code binnen methoden - dit is de gemakkelijkste vereiste
  • Bepalen welke entiteiten in het programma moeten worden opgenomen
  • Het programma correct opsplitsen in logische delen

Wat zit er achter deze concepten?

Het schrijven van goede code binnen methoden

Als je zelfs maar basisvaardigheden Engels hebt, is het je misschien opgevallen hoe gemakkelijk het soms kan zijn om code als Engelse zinnen te lezen:

  • class Cat extends Pet— Dit betekent dat de Cat-klasse de Pet-klasse uitbreidt
  • while(stream.ready())— zolang de stream klaar is...
  • if (a<b) return a; else return b— als akleiner is dan b, retourneer dan a, anders retourneer b.

Dit is opzettelijk. Java is een van de vele talen die het gemakkelijk maken om zelfdocumenterende code te schrijven, dwz code die zonder commentaar te begrijpen is. In goede Java-code lezen veel methoden net als Engelse zinnen.

Bij het schrijven van code is het jouw taak om het zo eenvoudig en beknopt mogelijk te maken. Denk er maar eens over na of uw code gemakkelijk te lezen is en u zult in de goede richting gaan.

In Java is het gebruikelijk om code te schrijven die gemakkelijk te lezen is. Bij voorkeur past alle code van een methode op één scherm (dwz 20-30 regels). Dit is de norm voor de hele Java-gemeenschap. Als de code kan worden verbeterd, moet deze worden verbeterd.

De beste manier om te leren hoe je goede code schrijft, is door te oefenen. Schrijf veel code, bestudeer de code van anderen en vraag meer ervaren collega's om jouw code te reviewen.

En onthoud dat op het moment dat je tegen jezelf zegt "laat goed genoeg met rust", je groei stopt.

Bepalen welke entiteiten in het programma moeten worden opgenomen

U moet code schrijven die andere programmeurs kunnen begrijpen. Als 9 van de 10 programmeurs klassen A, B en C zouden opnemen in het ontwerp van een programma, dan zou je ook klassen A, B en C in je programma moeten opnemen. U moet code schrijven die anderen kunnen begrijpen.

Geweldige, werkende, snelle, maar niet-standaard code is slechte code.

Je moet de projecten van anderen bestuderen: dit is de beste, snelste en gemakkelijkste manier om alle wijsheid op te snuiven die zich in de afgelopen decennia in de IT-industrie heeft verzameld.

En trouwens, je hebt al toegang tot een uitstekend, populair en goed gedocumenteerd project: de Java SDK . Begin ermee.

Analyseer de klassen en hoe ze zijn georganiseerd. Bedenk waarom sommige methoden statisch zijn en andere niet. Waarom hebben de methoden de specifieke parameters die ze hebben en andere niet? Waarom deze methoden precies, en waarom worden de klassen genoemd zoals ze heten, en waarom zijn ze opgenomen in hun specifieke pakketten.

Zodra u de antwoorden op al deze vragen begint te begrijpen, kunt u code schrijven die anderen kunnen begrijpen.

Dat gezegd hebbende, wil ik u waarschuwen tegen het analyseren van de code in de methoden van de Java SDK. Veel van de methoden zijn herschreven om de snelheid te maximaliseren, en hun leesbaarheid is twijfelachtig.

Het programma correct opsplitsen in logische delen

Vrijwel elk programma is opgedeeld in onderdelen of modules. Elk onderdeel is verantwoordelijk voor zijn eigen onderdeel van het programma.

Een computer heeft een moederbord, een monitor en een toetsenbord - dit zijn allemaal afzonderlijke, losjes gekoppelde onderdelen. Bovendien werken ze op gestandaardiseerde manieren samen: USB, HDMI, enz. Als je koffie op je toetsenbord morst, kun je het gewoon in de gootsteen afwassen, laten drogen en verder gebruiken.

Maar een laptop is een voorbeeld van een monolithische architectuur: het lijkt alsof we losse logische onderdelen kunnen onderscheiden, maar die zijn veel meer geïntegreerd. Op een MacBookPro moet je de helft van de laptop uit elkaar halen om het toetsenbord schoon te maken. En je koffie morsen op een laptop is een reden om een ​​nieuwe laptop te bestellen. Geen nieuwe kop koffie.


3. Je eigen klassen maken

Maar aangezien je net leert programmeren, moet je klein beginnen door te leren je eigen lessen te maken.

Natuurlijk heb je al klassen gemaakt, maar je moet leren begrijpen welke klassen in een programma moeten worden opgenomen, hoe ze moeten worden genoemd en welke methoden ze moeten hebben. En hoe ze met elkaar moeten omgaan.

Lijst van entiteiten

Als je niet weet waar je moet beginnen, begin dan bij het begin.

Wanneer u voor het eerst een programma begint te ontwerpen, kunt u gewoon een stuk papier pakken en een lijst opschrijven van de entiteiten (objecten) die in het programma zouden moeten staan. En schrijf vervolgens code volgens het principe dat elke entiteit een aparte klasse is.

Voorbeeld

Laten we zeggen dat je een schaakspel wilt schrijven. Je hebt de volgende entiteiten nodig: een schaakbord en 6 soorten schaakstukken. De stukken bewegen op verschillende manieren en hebben verschillende waarden. Logisch dat het aparte klassen zijn. Inderdaad, als je voor het eerst begint, hoe meer lessen, hoe beter.

Het komt zelden voor dat je een beginnende programmeur tegenkomt die tien lessen schrijft in plaats van twee. In plaats van tien lessen te schrijven, schrijven beginners graag twee lessen of misschien maar één. Dus schrijf alsjeblieft meer lessen, mijn collega-programmeurs. En je code wordt voor iedereen duidelijker behalve misschien voor jou 😛

Schaken

Stel dat we besluiten lessen voor schaken te schrijven: hoe zouden deze lessen eruit zien?

Is het schaakbord slechts een reeks van 8 bij 8? Het is beter om een ​​aparte klasse te maken die intern een verwijzing naar een array opslaat. Vervolgens kunt u tal van handige methoden aan de klasse "schaakbord" toevoegen, bijvoorbeeld om te controleren of een specifieke cel leeg of bezet is

Laat u in het algemeen altijd leiden door dit principe als u begint: een programma heeft verschillende entiteiten en een entiteit heeft een type. Dit type is de klasse.


4. Statische variabelen en methoden

Vergeet ook niet om statische variabelen en methoden te gebruiken. Als je een schaakstuk hebt dat interactie heeft met een ander op het schaakbord, dan heeft je code een methode nodig die zowel naar het eerste en tweede stuk als naar het schaakbord verwijst.

Statische variabelen, die overal in het programma toegankelijk zijn, worden meestal gebruikt om te voorkomen dat er voortdurend verwijzingen worden doorgegeven naar objecten die "altijd bestaan".

Bijvoorbeeld als volgt:

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


Een verwijzing naar een enkel ChessBoardobject.
Een 8x8 tweedimensionale array, geen statische variabele.








Voeg de stukken toe aan het bord.

Of in plaats van een statische variabele kunt u een methode maken die een singleton-object retourneert. Bijvoorbeeld als volgt:

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