1. Objetos e classes

Hoje você aprenderá um pouco sobre como funciona um programa típico em Java. Aqui está a grande novidade: todo programa Java consiste em classes e objetos.

Você já sabe o que são classes, mas o que são objetos?

Vou começar com uma analogia. Imagine que você quer fazer um pequeno navio. Primeiro você precisa criar um projeto e depois entregá-lo à fábrica, onde um navio será construído de acordo com o projeto. Ou talvez uma dúzia. Ou quantos navios quiser. Dezenas de naves idênticas são construídas de acordo com um único projeto. Isso é o importante aqui.

É o mesmo na programação Java.

Plantas

Um programador é como um designer. Um designer cria projetos e um programador Java escreve classes. As peças são criadas com base nos projetos e os objetos são criados com base nas classes.

Primeiro, escrevemos classes (fazemos projetos) e, à medida que o programa é executado, a máquina Java cria objetos com base nessas classes. Da mesma forma que os navios são criados a partir de projetos.

Existe apenas um projeto, mas pode haver muitos navios. Os navios são distintos - eles têm nomes diferentes e carregam cargas diferentes. Mas eles são muito parecidos: todos compartilham o mesmo design e podem executar tarefas semelhantes.

Ou aqui está outra analogia...

Formigueiro

Um formigueiro é um bom exemplo de como os objetos interagem. Existem três classes de formigas em um formigueiro simples: a rainha, soldados e trabalhadores.

O número de formigas de cada classe é diferente. Há uma única rainha para todo o formigueiro, mas há dezenas de soldados e centenas de formigas operárias. Três classes e centenas de objetos. As formigas interagem umas com as outras — com formigas de sua mesma classe e com formigas de outras classes — de acordo com regras rígidas.

Este é o exemplo perfeito. Tudo é exatamente assim em um programa típico. Existe um objeto primário que cria objetos de todas as outras classes. Os objetos começam a interagir entre si e com o "mundo externo" do programa. O comportamento dos objetos é codificado internamente.

Essas duas analogias são dois lados da mesma moeda. A verdade está no meio. O primeiro exemplo (sobre um projeto e navios) mostra o relacionamento entre uma classe e os objetos dessa classe. Esta é uma forte analogia. O segundo exemplo (sobre um formigueiro) mostra a relação entre as classes escritas e os objetos que existem à medida que o programa é executado.

Você deve primeiro escrever classes para cada objeto que existirá no programa e, em seguida, também descrever como eles interagem. Sim, está certo, mas é mais fácil do que parece.

Em Java, todas as entidades são objetos em tempo de execução, e escrever um programa é descrever as diferentes maneiras pelas quais os objetos interagem. Os objetos simplesmente chamam os métodos uns dos outros e passam os dados necessários para eles.

Documentação

E como você sabe quais dados passar para os métodos? As pessoas que vieram antes de você pensaram em tudo.

Cada classe normalmente tem uma descrição que diz para o que foi criada. Além disso, cada método público geralmente possui uma descrição que indica o que ele faz e quais dados precisam ser passados ​​para ele.

Para usar uma classe, você precisa ter uma ideia geral do que ela faz. E você precisa saber exatamente o que cada método faz. Mas você não precisa saber como isso acontece. É como uma varinha mágica.

Vamos dar uma olhada no código para copiar um arquivo:

Copiando o arquivo c:\\data.txt para o arquivo 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 você ler este código linha por linha, poderá adivinhar o que ele faz em termos gerais. Embora isso exija experiência e prática. Depois de um tempo, esse código parecerá familiar e compreensível para você.


2. Projetando um programa

O design do programa é uma arte completa. É simultaneamente simples e difícil. Simples, porque não há leis rígidas: tudo o que não é proibido é permitido. Bem, e é também isso que dificulta: existem muitas maneiras de fazer algo e não é fácil encontrar a melhor.

Projetar um programa é como escrever um livro. Por um lado, você apenas escreve letras, palavras e frases. Por outro lado, são importantes o enredo, os personagens, as contradições internas, os conflitos, o estilo de contar a história, as intrigas, etc.

O principal é entender para quem você está escrevendo o código. E você escreve código para outros programadores .

O desenvolvimento de produtos inevitavelmente significa fazer mudanças: algo é adicionado aqui, algo removido ali, algo é redesenhado. É assim que projetos grandes, enormes e gigantescos nascem de pequenas iterações.

O que mais importa para o código é que ele seja compreensível para outros programadores. O código incorreto que é compreensível pode ser corrigido. Código correto, mas incompreensível, não pode ser melhorado.  Tudo o que você pode fazer é descartá-lo.

Então, como você escreve um código bom e limpo?

Fazer isso requer três coisas:

  • Escrever um código bom e compreensível dentro de métodos — esse é o requisito mais fácil
  • Decidir quais entidades devem ser incluídas no programa
  • Dividindo o programa em partes lógicas corretamente

O que está por trás desses conceitos?

Escrevendo um bom código dentro de métodos

Se você tem habilidades básicas de inglês, deve ter notado como às vezes pode ser fácil ler o código como frases em inglês:

  • class Cat extends Pet— Isso significa que a classe Cat estende a classe Pet
  • while(stream.ready())— contanto que o stream esteja pronto...
  • if (a<b) return a; else return b— se afor menor que b, então retorne a, caso contrário retorne b.

Isso é deliberado. Java é uma das várias linguagens que facilitam a escrita de código autodocumentado, ou seja, código compreensível sem comentários. Em um bom código Java, muitos métodos são lidos como sentenças em inglês.

Ao escrever código, sua tarefa é torná-lo o mais simples e conciso possível. Basta pensar se o seu código é fácil de ler e você começará a se mover na direção certa.

Em Java, é comum escrever códigos fáceis de ler. De preferência, todo o código de um método caberá em uma única tela (ou seja, 20 a 30 linhas). Esta é a norma para toda a comunidade Java. Se o código pode ser melhorado, deve ser melhorado.

A melhor maneira de aprender a escrever um bom código é por meio da prática. Escreva muito código, estude o código de outras pessoas e peça a colegas mais experientes para revisar seu código.

E lembre-se de que no momento em que você diz a si mesmo "deixe tudo em paz", seu crescimento para.

Decidir quais entidades devem ser incluídas no programa

Você precisa escrever um código que outros programadores possam entender. Se 9 entre 10 programadores incluírem as classes A, B e C no design de um programa, você também deve criar as classes A, B e C em seu programa. Você deve escrever um código que outros possam entender.

Ótimo, funcionando, rápido, mas código fora do padrão é um código ruim.

Você precisa estudar os projetos de outras pessoas: essa é a maneira melhor, mais rápida e mais fácil de absorver toda a sabedoria acumulada na indústria de TI há décadas.

Aliás, você já tem acesso a um projeto excelente, popular e bem documentado — o Java SDK . Comece com isso.

Analise as classes e como elas são organizadas. Pense por que alguns métodos são estáticos e outros não. Por que os métodos têm os parâmetros específicos que possuem, mas não outros. Por que exatamente esses métodos e por que as classes são nomeadas como são nomeadas e por que estão contidas em seus pacotes específicos.

Depois de começar a entender as respostas para todas essas perguntas, você será capaz de escrever um código que outras pessoas possam entender.

Dito isso, quero alertá-lo contra a análise do código nos métodos do Java SDK. Muitos dos métodos foram reescritos para maximizar a velocidade e sua legibilidade é questionável.

Dividindo o programa em partes lógicas corretamente

Quase todos os programas são divididos em partes ou módulos. Cada parte é responsável por seu próprio aspecto do programa.

Um computador tem uma placa-mãe, um monitor e um teclado – todas essas partes são separadas e fracamente acopladas. Além disso, eles interagem de maneira padronizada: USB, HDMI etc. Se derramar café no teclado, basta lavá-lo na pia, deixar secar e continuar usando.

Mas um laptop é um exemplo de arquitetura monolítica: parece que podemos discernir partes lógicas separadas, mas elas são muito mais integradas. Em um MacBookPro, você precisa desmontar metade do laptop para limpar o teclado. E derramar café em um laptop é um motivo para comprar um novo laptop. Não é uma nova xícara de café.


3. Criando suas próprias classes

Mas como você está apenas aprendendo a programar, deve começar aos poucos aprendendo a criar suas próprias classes.

Claro, você já criou classes, mas precisa aprender a entender quais classes devem ser incluídas em um programa, como devem ser nomeadas e quais métodos devem ter. E como eles devem interagir uns com os outros.

Lista de entidades

Se você não sabe por onde começar, comece do começo.

Quando você começa a projetar um programa, você pode simplesmente pegar um pedaço de papel e escrever uma lista das entidades (objetos) que devem estar no programa. E então escreva o código de acordo com o princípio de que cada entidade é uma classe separada.

Exemplo

Digamos que você queira escrever um jogo de xadrez. Você precisará das seguintes entidades: um tabuleiro de xadrez e 6 tipos de peças de xadrez. As peças se movem de maneiras diferentes e têm valores diferentes. Faz sentido que sejam classes separadas. De fato, quando você começar, quanto mais aulas, melhor.

É muito raro encontrar um programador iniciante que escreva dez classes em vez de duas. Em vez de escrever dez aulas, os iniciantes adoram escrever duas aulas ou talvez apenas uma. Então, por favor, escrevam mais classes, meus colegas programadores. E seu código ficará mais claro para todos, exceto talvez para você 😛

Xadrez

Suponha que, digamos, decidamos escrever classes para xadrez: como seriam essas classes?

O tabuleiro de xadrez é apenas uma matriz de 8 por 8? É melhor criar uma classe separada que armazene internamente uma referência a um array. Então você pode adicionar vários métodos úteis à classe "tabuleiro de xadrez", por exemplo, para verificar se uma célula específica está vazia ou ocupada

Em geral, ao começar, sempre se guie por este princípio: um programa tem várias entidades e uma entidade tem um tipo. Este tipo é a classe.


4. Variáveis ​​estáticas e métodos

Também não se esqueça de usar variáveis ​​e métodos estáticos. Se você tiver uma peça de xadrez interagindo com outra no tabuleiro de xadrez, seu código precisará de um método que use referências à primeira e à segunda peças, bem como ao tabuleiro de xadrez.

As variáveis ​​estáticas, que podem ser acessadas de qualquer lugar no programa, são normalmente usadas para evitar a passagem constante de referências a objetos que "sempre existem".

Por exemplo, assim:

Código Observação
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);
      ...
   }
}


Uma referência a um único ChessBoardobjeto.
Uma matriz bidimensional 8x8, não uma variável estática.








Adicione as peças ao tabuleiro.

Ou, em vez de uma variável estática, você pode criar um método que retorne um objeto singleton. Por exemplo, assim:

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