1. Objetos y clases

Hoy aprenderá un poco sobre cómo funciona un programa Java típico. Aquí está la gran noticia: cada programa Java se compone de clases y objetos.

Ya sabes qué son las clases, pero ¿qué son los objetos?

Empezaré con una analogía. Imagina que quieres hacer un barco pequeño. Primero debe crear un plano y luego dárselo a la fábrica, donde se construirá un barco de acuerdo con el plano. O tal vez una docena. O tantos barcos como quieras. Se construyen docenas de barcos idénticos de acuerdo con un solo plano. Eso es lo importante aquí.

Es lo mismo en la programación Java.

Planos

Un programador es como un diseñador. Un diseñador crea planos y un programador de Java escribe clases. Las piezas se crean en función de los planos y los objetos se crean en función de las clases.

Primero, escribimos clases (hacemos planos) y luego, mientras se ejecuta el programa, la máquina Java crea objetos basados ​​en estas clases. De la misma manera que los barcos se crean a partir de planos.

Solo hay un plano, pero puede haber muchos barcos. Los barcos son distintos: tienen nombres diferentes y transportan cargas diferentes. Pero son muy similares: todos comparten el mismo diseño y pueden realizar tareas similares.

O aquí hay otra analogía...

Hormiguero

Un hormiguero es un buen ejemplo de cómo interactúan los objetos. Hay tres clases de hormigas en un hormiguero simple: la reina, los soldados y los trabajadores.

El número de hormigas de cada clase es diferente. Hay una sola reina para todo el hormiguero, pero hay docenas de soldados y cientos de hormigas obreras. Tres clases y cientos de objetos. Las hormigas interactúan entre sí, con hormigas de su misma clase y con hormigas de otras clases, de acuerdo con reglas rígidas.

Este es el ejemplo perfecto. Todo es exactamente así en un programa típico. Hay un objeto primario que crea objetos de todas las demás clases. Los objetos comienzan a interactuar entre sí y con el "mundo exterior" del programa. El comportamiento de los objetos está codificado internamente.

Estas dos analogías son dos caras de la misma moneda. La verdad está en el medio. El primer ejemplo (sobre un plano y barcos) muestra la relación entre una clase y los objetos de esa clase. Esta es una fuerte analogía. El segundo ejemplo (sobre un hormiguero) muestra la relación entre las clases escritas y los objetos que existen mientras se ejecuta el programa.

Primero debe escribir clases para cada objeto que existirá en el programa y luego también describir cómo interactúan. Sí, así es, pero es más fácil de lo que parece.

En Java, todas las entidades son objetos en tiempo de ejecución, y escribir un programa consiste en describir las diferentes formas en que interactúan los objetos. Los objetos simplemente llaman a los métodos de los demás y les pasan los datos requeridos.

Documentación

¿Y cómo sabes qué datos pasar a los métodos? Las personas que vinieron antes que tú pensaron en todo.

Cada clase normalmente tiene una descripción que dice para qué fue creada. Además, cada método público suele tener una descripción que indica qué hace y qué datos se le deben pasar.

Para usar una clase, necesita tener una idea general de lo que hace. Y necesita saber exactamente lo que hace cada método. Pero no es necesario que sepas cómo lo hace. Es como una varita mágica.

Echemos un vistazo al código para copiar un archivo:

Copiar el archivo c:\\data.txt al archivo 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();
   }
}

Si lee este código línea por línea, puede adivinar lo que hace en términos generales. Aunque eso requiere experiencia y práctica. Después de un tiempo, este código le resultará familiar y comprensible.


2. Diseño de un programa

El diseño de programas es todo un arte. Es a la vez simple y difícil. Sencillo, porque no hay leyes estrictas: todo lo que no está prohibido está permitido. Bueno, y eso es también lo que lo hace difícil: hay muchas maneras de hacer algo y no es fácil encontrar la mejor.

Diseñar un programa es como escribir un libro. Por un lado, solo escribes letras, palabras y oraciones. Por otro lado, son importantes la trama, los personajes, las contradicciones internas, los conflictos, el estilo narrativo, la intriga, etc.

Lo principal es entender para quién estás escribiendo el código. Y escribes código para otros programadores .

El desarrollo de productos significa inevitablemente hacer cambios: se agrega algo aquí, se elimina algo allá, se rediseña algo. Así nacen grandes, enormes y gigantescos proyectos a partir de pequeñas iteraciones.

Lo más importante para el código es que debe ser comprensible para otros programadores. El código incorrecto que es comprensible se puede corregir. El código correcto pero incomprensible no se puede mejorar.  Todo lo que puedes hacer es descartarlo.

Entonces, ¿cómo se escribe un código bueno y limpio?

Hacer esto requiere tres cosas:

  • Escribir código bueno y comprensible dentro de los métodos: este es el requisito más fácil
  • Decidir qué entidades deben incluirse en el programa
  • Dividir el programa en partes lógicas correctamente

¿Qué hay detrás de estos conceptos?

Escribir buen código dentro de los métodos

Si tiene conocimientos básicos de inglés, es posible que haya notado lo fácil que puede ser leer el código como oraciones en inglés a veces:

  • class Cat extends Pet— Esto significa que la clase Gato amplía la clase Mascota
  • while(stream.ready())— mientras la transmisión esté lista...
  • if (a<b) return a; else return b— si aes menor que b, entonces devuelve a, de lo contrario devuelve b.

Esto es deliberado. Java es uno de varios lenguajes que facilitan la escritura de código autodocumentado, es decir, código comprensible sin comentarios. En un buen código Java, muchos métodos se leen como oraciones en inglés.

Al escribir código, su tarea es hacerlo lo más simple y conciso posible. Solo piense si su código es fácil de leer y comenzará a moverse en la dirección correcta.

En Java, se acostumbra escribir código que sea fácil de leer. Preferiblemente, todo el código de un método cabrá en una sola pantalla (es decir, 20-30 líneas). Esta es la norma para toda la comunidad de Java. Si el código se puede mejorar, debe mejorarse.

La mejor manera de aprender a escribir un buen código es a través de la práctica. Escriba mucho código, estudie el código de otros y solicite a colegas más experimentados que revisen su código.

Y recuerda que en el momento en que te dices a ti mismo "déjalo en paz", tu crecimiento se detiene.

Decidir qué entidades deben incluirse en el programa

Necesitas escribir código que otros programadores puedan entender. Si 9 de cada 10 programadores incluirían las clases A, B y C en el diseño de un programa, entonces también debería incluir las clases A, B y C en su programa. Debe escribir código que otros puedan entender.

Genial, funcional, rápido, pero el código no estándar es un código malo.

Necesitas estudiar los proyectos de otras personas: esta es la forma mejor, más rápida y más fácil de absorber toda la sabiduría que se ha acumulado en la industria de TI durante décadas.

Y, por cierto, ya tiene acceso a un proyecto excelente, popular y bien documentado: el SDK de Java . Comience con eso.

Analizar las clases y cómo están organizadas. Piense por qué algunos métodos son estáticos y otros no. ¿Por qué los métodos tienen los parámetros específicos que tienen pero no otros? Por qué estos métodos exactamente, y por qué las clases se llaman como se llaman, y por qué están contenidas en sus paquetes específicos.

Una vez que comience a comprender las respuestas a todas estas preguntas, podrá escribir código que otros puedan entender.

Dicho esto, quiero advertirle que no analice el código en los métodos del SDK de Java. Muchos de los métodos se reescribieron para maximizar la velocidad y su legibilidad es cuestionable.

Dividir el programa en partes lógicas correctamente

Casi todos los programas se dividen en partes o módulos. Cada parte es responsable de su propio aspecto del programa.

Una computadora tiene una placa base, un monitor y un teclado; todas estas son partes separadas y poco acopladas. Además, interactúan de formas estandarizadas: USB, HDMI, etc. Si derrama café sobre su teclado, simplemente puede lavarlo en el fregadero, dejarlo secar y luego continuar usándolo.

Pero una computadora portátil es un ejemplo de arquitectura monolítica: parece que podemos discernir partes lógicas separadas, pero están mucho más integradas. En una MacBookPro, debe desmontar la mitad de la computadora portátil para limpiar el teclado. Y derramar su café en una computadora portátil es una razón para pedir una nueva computadora portátil. Ni una nueva taza de café.


3. Creando tus propias clases

Pero como solo está aprendiendo a programar, debe comenzar poco a poco aprendiendo a crear sus propias clases.

Por supuesto, ya ha creado clases, pero debe aprender a comprender qué clases deben incluirse en un programa, cómo deben nombrarse y qué métodos deben tener. Y cómo deben interactuar entre sí.

Lista de entidades

Si no sabes por dónde empezar, empieza desde el principio.

Cuando comienza a diseñar un programa por primera vez, puede simplemente tomar una hoja de papel y escribir una lista de las entidades (objetos) que deberían estar en el programa. Y luego escriba el código de acuerdo con el principio de que cada entidad es una clase separada.

Ejemplo

Digamos que quieres escribir un juego de ajedrez. Necesitarás las siguientes entidades: un tablero de ajedrez y 6 tipos de piezas de ajedrez. Las piezas se mueven de diferentes maneras y tienen diferentes valores. Tiene sentido que sean clases separadas. De hecho, cuando empiezas, cuantas más clases, mejor.

Es muy raro encontrar a un programador novato que escriba diez clases en lugar de dos. En lugar de escribir diez clases, a los principiantes les encanta escribir dos clases o quizás solo una. Así que por favor escriban más clases, mis compañeros programadores. Y tu código será más claro para todos excepto quizás para ti 😛

Ajedrez

Supongamos que decidimos escribir clases de ajedrez: ¿cómo serían estas clases?

¿El tablero de ajedrez es solo una matriz de 8 por 8? Es mejor crear una clase separada que almacene internamente una referencia a una matriz. Luego puede agregar muchos métodos útiles a la clase "tablero de ajedrez", por ejemplo, para verificar si una celda específica está vacía u ocupada

En general, cuando comience, guíese siempre por este principio: un programa tiene varias entidades y una entidad tiene un tipo. Este tipo es la clase.


4. Variables y métodos estáticos

Además, no olvide usar variables y métodos estáticos. Si tiene una pieza de ajedrez interactuando con otra en el tablero de ajedrez, entonces su código necesita un método que tome referencias a la primera y segunda piezas, así como al tablero de ajedrez.

Las variables estáticas, a las que se puede acceder desde cualquier parte del programa, se utilizan normalmente para evitar pasar constantemente referencias a objetos que "siempre existen".

Por ejemplo, así:

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


Una referencia a un solo ChessBoardobjeto.
Una matriz bidimensional de 8x8, no una variable estática.








Añade las piezas al tablero.

O en lugar de una variable estática, puede crear un método que devuelva un objeto único. Por ejemplo, así:

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