Java desde Cero – Sobrecarga de Constructores – Clases y Métodos

Recordemos que un constructor otorga un estado inicial a las propiedades de la clase; sin embargo, existirá ocasiones en que una misma instancia de clase deseemos que se inicie de distintas formas, hacer que una clase pueda inicializarse de distintas formas se logra a través de la sobrecarga de constructores, la sobrecarga de constructores sea método o de clase es la creación de varios constructores  o métodos con el mismo nombre pero con diferente lista de tipos de parámetros o número de ellos, si no lo haces el compilador de Java no sabría a que constructor estás haciendo referencia y lanzaría un error.

¿Cuántos constructores por clase podemos crear?, pues siempre que se cumpla la condición mencionada, podría ser incluso infinito. Revisemos un ejemplo de gatitos:

package clases;
/**
 * Gatos
 */

public class Gatos {
    public static void main(String[] args) {
        Gatos gatito1=new Gatos();
        Gatos gatito2=new Gatos("Asrael", 10);
        System.out.println("Gatito 1 se llama: " + gatito1.nombre);
        System.out.println("Gatito 2 su edad es: "+  gatito2.nombre);
        gatito1.cambiar();
        gatito2.cambiar("Cielo");
        System.out.println("Gatito 1 se llama: " + gatito1.nombre);
        System.out.println("Gatito 2 su edad es: "+  gatito2.nombre);

    }

    String nombre;
    int edad;
    public Gatos(){
        this.nombre="Michifus";
        this.edad=7;
    }

    public Gatos(String nombre, int edad){
        this.nombre=nombre;
        this.edad=edad;
    }

    String cambiar(){
        this.nombre="Juanelo";
        return this.nombre;
    }

    String cambiar(String nuevo_nombre){
        this.nombre=nuevo_nombre;
        return this.nombre;
    }
}

Analicemos el ejemplo en cuestión, hemos creado una clase llamada Gatos, la clase tiene propiedades como el nombre y la edad, luego de ello creamos el primer constructor, el primer constructor no requiere de parámetros, asigna arbitrariamente valores de inicio a las propiedades descritas; el segundo constructor como observamos sí recibe parámetros, en este caso del nombre y la edad; luego de ello de similar forma al constructor creamos dos métodos que modificarán el nombre de nuestras instancias, observemos que retornan el valor que modifican, no hemos colocado en modo private a las propiedades es por ello que podemos acceder a ella. Finalmente en el método main hemos creado instancias de la clase haciendo uso de los 2 constructores y luego llamando a los mismos métodos, en ambos casos imprimiendo los resultados antes de ejecutar un cambio y posterior a ello. Demos algunos detalles más sobre este asunto, imaginemos que tenemos el siguiente método:

public void unNumero(int numero){ //código}
public void unNumero(float numero){//código}

La diferencia entre ellos es el tipo de argumento que reciben, tenlo mucho en cuenta. Otro asunto que debes considerar es que el tipo de retorno NO sirve para distinguir métodos. Si dos métodos tienen el mismo número de argumentos con tipos iguales nos lazará un error en tiempo de compilación:

public int unNumero(int numero){ //código}
public float unNumero(float numero){//código}

Ahora ¿Qué ocurre si creamos un constructor de la siguiente forma?:

  public Gatos(String nombre){
        this.nombre=nombre;
    } 

Tenemos un constructor que solo debemos de ingresar el nombre y que si intentamos hacer:

 System.out.println("Gatito 3 su edad es: "+  gatito3.nombre+ " y la edad es: "+gatito3.edad); 

Observaremos que la edad nos arroja un valor igual a cero, y esto porque no hemos asignado un valor inicial a la edad en este constructor, ¿Qué ocurre que si de igual forma queremos que tome un valor por defecto?, primera solución revisada fue inicializar por defecto, pero la segunda es hacer uso del this:

 public Gatos(String nombre){
        this(nombre,7);
    } 

¿Qué estamos haciendo?, pues estamos llamando a un constructor hecho ya de la clase, aquí quizá no se aprecie mucho dado que solo tenemos 3 constructores, pero ¿Qué constructor es el que se ha de llamar?, pues del que coincida tanto en el tipo como cantidad de parámetros que incluyamos en el this.

Creación de una Aplicación en P5.Js y Socket.io – Parte 2

Anteriormente parte 1

VIENDO EL ARCHIVO MAIN.JS

Recordemos que nuestro principal objetivo es tener una aplicación donde exista una grilla de cuadrados los cuales pueden ser pintados desde un menú de colores haciendo click en un color y luego click en el cuadrado que se desea pintar, esto debe ser comunicado a los demás clientes que se hayan conectado a nuestra aplicación, además cualquier cliente puede nuevamente pintar el mismo cuadrado; recordemos que una condición es que esta grilla se pueda renderizar de forma adecuada sin importar el dispositivo, la dimensión y el aspecto está totalmente controlado por P5Js; sin embargo, P5Js hace uso de valores absolutos en pixeles tal que si definimos que un cuadrado tenga 120×120 pixeles en un computador de mesa podría verse bien dada las dimensiones del mismo, pero eso no ocurriría en un teléfono móvil; para ello debemos hacer uso de ciertos artilugios que permitan la renderización .

MANOS AL CÓDIGO

Lo primero entonces es declarar una serie de variables globales las cuáles serán accesibles en todo la aplicación por lo mismo que son globales, entonces:

var socket=io();
var dx=5*window.innerWidth/6; //variable general del ancho
var dy=5*window.innerHeight/6; //variable general del alto

Cuando se realizó la comunicación desde el servidor con socket.io() este puso a disposición un socket que nos permitirá emitir y escuchar eventos, luego de ello debemos de trabajar en función de proporciones, window.innerWidth y window.innerHeight nos da la dimensión en ancho y alto de la ventana de la ventana del dispositivo, de ello nuestra aplicación cogerá los 5/6. Si dx y dy son las dimensiones de nuestra aplicación, podemos entonces segmentarla como un grilla, tal que en vertical sean once espacios y en horizontal sean 10 espacios:

2.png

var grilla_y=11;
var grilla_x=10;

Podemos obtener la dimensión de cada grilla haciendo:

var w_c=dx/grilla_x; // variable del ancho de un cuadrado
var h_c=dy/grilla_y; //variable del alto de un cuadrado 

Como hemos de crear una grilla de cuadrados, lo ideal es almacenarlo en un arreglo, tal que podamos acceder a su posición, así también recordemos que los cuadrados tienen como propiedad un id que tiene la misma estructura de la posición en el arreglo:

var malla_cuadrados=[]; //cuadrícula de cuadrados
var mando_colores=[]; // cuadrícula de botones de asignación de color

Finalmente creamos una variable global relacionada al color sin inicializar, y su función principal es almacenar y comunicar el color que se ha elegido

var color_actual;

P5Js tiene dos funciones básicas principales, setup y draw, la primera es llamada cuando el programa inicia y es la encargada de inicializar todas las variables o configuraciones de entorno que nuestra aplicación requiera, la segunda es la encargada de ejecutar infinitamente el código que se inserte en el, lo cual será de mucha utilidad cuando se tenga que repintar un cuadrado ante un cambio de color.

Función Setup

Lo primero que debemos hacer en esta función es crear el canvas, el canvas es el lienzo sobre el cual se ha de dibujar todos nuestros elementos:

let canvas=seteo_canvas(dx,dy);

¿Pero qué hace la función seteo_canvas(), como observamos recibe la dimensión de nuestra aplicación y hace lo siguiente:

function seteo_canvas(){
    let canvas=createCanvas(dx,dy);
    let posx=(windowWidth-width)/2;
    let posy=(windowHeight-height)/2;
    canvas.position(posx, posy);
    canvas.parent("juego");
    return canvas

}

P5Js  usa el método createCanvas que recibe las dimensiones del canvas, si lo dejamos tal cual, posicionará el canvas en la esquina superior izquierda creando un nuevo tag canvas, pero queremos controlar ello, esto lo hacemos indicando la posición tanto en X e Y usando las variables que nos proporciona P5Js que son windowWidth que nos da el ancho de la ventana y width que nos proporciona el ancho de nuestra aplicación, similar a lo que hicimos para hallar dx, solo que en términos de P5Js y que con el método position le daríamos una posición, finalmente lo asociamos al tag main de nuestro index.html a través del método parent que recibe un id y devolvemos un canvas ya configurado.

Luego de crear el canvas debemos de crear la grilla de cuadrados, al ser una grilla posicionarlo se hará a través de un bucle for anidado tal que en cada iteración del bucle anidado se genere una instancia de la clase cuadrados y se guarde en malla_cuadrados:

for(fila=0;fila<grilla_y-1;fila++){
        for(columna=0;columna<grilla_x;columna++){
            let c=new Cuadrados(w_c/2+w_c*columna,h_c/2+h_c*fila,w_c,h_c,fila,columna);
            malla_cuadrados.push(c);       
        }
    }

Observemos 1 cuadrado:

let c=new Cuadrados(w_c/2+w_c*columna,h_c/2+h_c*fila,w_c,h_c,fila,columna);

Cada w_c es un segmento de la grilla, como el cuadrado está centrado le damos como primera posición la mitad de un segmento de grilla, y el cual aumenta en un segmento en cada iteración de columna, de forma similar con la posición Y solo que con la fila. Observamos además que la grilla es de 10×10, ya que el último nivel lo reservamos para el menú de colores.

Función menu_colores

Vamos a crear una línea divisoria haciendo uso de la función line(), le asignamos la posición inferior un grosor de línea de 4 (strokeWeight) y un color con stroke(), también una lista de colores en formato RGB haciendo uso de color, y finalmente tan igual que la creación de cuadrados, los creamos a través del uso de bucle for.

function menu_colores(){
    //Línea divisoria
    stroke(155,56,89);//color de línea
    strokeWeight(4);
    line(0, (grilla_y-1)*h_c-2,grilla_x*w_c,(grilla_y-1)*h_c-2);
    //Fin de línea divisoria
    //cuadrados de mando
    strokeWeight(1);
    noStroke();
    lista_colores=[color(19,22,76),color(19,76,40),color(196,47,11),color(242,245,2),color(255)]
    for (let i = 0; i < 5; i++) {
        fill(lista_colores[i]);
        rectMode(CENTER);
        let rectangulo=rect(w_c/2+(w_c)*i, (grilla_y-1)*h_c+h_c/2, w_c, h_c);    
        mando_colores.push(rectangulo);
    }

}

Función Draw

Recordemos que draw es la función que va iterar infinitamente, por ende es la encargada de la actualización de estado de nuestros cuadrados los cuáles cambiarán de color, para ello debemos de dibujar los cuadrados, para dibujar los cuadrados tenemos el método de la clase que es dibujar cuadrado, luego de ello dibujamos el menú de colores:

function draw(){
    malla_cuadrados.forEach(cuadrado=>{
        cuadrado.dibujarCuadrado();
    });
    menu_colores();    
}

 

Hemos utilizado el bucle forEach el cual recorrerá por cada elemento (que es un cuadrado) y llamará al método dibujar cuadrado, luego se ejecutará la función de los colores. Hasta este punto solo tendremos la grilla de cuadrados y el menú de de colores puestos en la escena, Ahora debemos de estar a la escucha de los eventos, para ello P5Js puede registrar una serie de eventos relacionados al ratón, ¿Cuál de esos eventos necesitamos?, pues el evento que sucede cuando   el botón del ratón ha sido presionado y suelto  el cual se registra en la función mouseClicked().

Función mouseClicked

Al no ser un botón, no se puede asignar un “listener“, y mouseClicked registrará cualquier evento que implique un presionar y soltar del ratón en toda la pantalla, debemos de ser un poco más creativos para determinar cuando se presionó un cuadrado específico o si fue el cuadro de colores, para ello ante el evento debemos de rastrear toda la grilla, tanto de cuadrados como de colores y determinar la posición del ratón en X e Y de donde se generó el evento:

function mouseClicked(){
    //Grid de cuadrados
    for(let fila=0;fila<(dy/h_c)-1;fila++){
        for(let columna=0;columna<dx/w_c;columna++){
            if((w_c*columna<mouseX && mouseX<w_c*(columna+1)) &&(h_c*fila<mouseY && mouseY<h_c*(fila+1))){
                //console.log(" fila: ", fila+1," columna: ",columna+1 );
                let pos_aux=columna+(grilla_y-1)*fila;
                let aux_x=malla_cuadrados[pos_aux].x;
                let aux_y=malla_cuadrados[pos_aux].y;
                let aux_cuadrado=new Cuadrados(aux_x,aux_y,w_c,h_c,fila,columna,color_actual);
                aux_cuadrado.dibujarCuadrado();
                malla_cuadrados[pos_aux]=aux_cuadrado;
                //el socekt emite
                socket.emit("dibujar",{id:pos_aux,mi_color:malla_cuadrados[pos_aux].mi_color}) ;
                //console.log(malla_cuadrados[pos_aux].id);
            }
        }
    }

    //Grid de mandos
    colores=[{r:19,g:22,b:76},{r:19,g:76,b:40},{r:196,g:47,b:11},{r:242,g:245,b:2},{r:255,g:255,b:255}];
    if(mouseY>(grilla_y-1)*h_c && mouseY<grilla_y*h_c){
        for(let columna=0;columna<dx/w_c;columna++){
            if(w_c*columna<mouseX && mouseX<w_c*(columna+1)){
                color_actual=colores[columna];
                //console.log(color_actual); revisamos si el color actual está cambiando
            }
        }
    }
}

En la grilla de cuadrados hemos ejecutado el doble bucle for, note el artilugio sobre la condición del límite (dv/h_c)-1, dv: es el área de trabajo, y h_c: es un segmento de la grilla, esta división y resta posterior es 10, ¿Por qué usar esta forma y no 10 a secas?, pues porque tu grilla puede variar, así no tendrías que estar modificando todo el código, de forma similar ocurre con (dx/w_c). Ahora revisemos el condicional, como deseamos saber la posición del ratón, esta la podemos obtener con los eventos mouseX y mouseY de P5Js, pero no solo ello, también si está en un segmento específico de la grilla, es por ello que tenemos w_c*columna y h_c*fila, ¿Por qué en un condicional?, pues porque podemos hacer click fuera del área de trabajo, debemos asegurar que el click se hizo dentro del área de trabajo y en un cuadrado específico, cuando obtenemos ello, almacenamos la posición, la posición  la buscamos dentro de malla cuadrados obteniendo la posición X e Y, creamos un nuevo cuadrado en la misma posición, fila y columna, con un detalle, ahora sí agregamos el parámetro del color asignando el valor de la variable color_actual, esto lo hacemos el siguiente fin, recordemos que color_actual tiene como función almacenar un color, por defecto es blanco y solo varía cuando un color del cuadro de colores ha sido seleccionado, esto responde a la siguiente dinámica:

“El usuario selecciona un color modificando el valor de color_actual, el usuario luego de seleccionar un color, selecciona un cuadrado de la grilla para modificar el color, se modifica el color creando una nueva instancia de cuadrado asignando como parámetro de color el valor de la variable color_actual”

Cuando se crea una instancia de cuadrado esta reemplaza al cuadrado anterior en su posición en el arreglo de malla_cuadrados. Vemos ya en acción el registro del evento emit, vamos a emitir dibujar enviando al servidor para que retransmita a todos los clientes el cambio de color en una posición indicada que se almacena en la propiedad id.

En la grilla de mandos o cuadro de colores, la misma dinámica de detección de la posición del ratón; sin embargo, tenemos un arreglo de colores que en función de la posición iremos asignando a la variable global color_actual.

El socket a la Escucha del evento personalizado

Hasta el momento hemos localizado la posición donde se genera un evento, hemos comunicado el evento y sus parámetros a los demás clientes, pero también la siguiente perspectiva en que un mismo clientes está emitiendo y estando a la escucha de los eventos registrados, esto ya lo habíamos revisado en el servidor, toca entonces en el cliente poner a la escucha, sabemos que el evento registrado es “redibujar

socket.on("redibujar",(datos)=>{
    console.log(datos);
    malla_cuadrados.forEach(cuadrado=>{
        if(cuadrado.id==datos.id){
            cuadrado.mi_color=datos.mi_color;
        }
    })
})

Cuando el evento es comunicado el cliente recibe los datos y recorre el arreglo de malla_cuadrados, buscando a través del id, cuando estos sean iguales, modificaremos la propiedad mi_color del cuadrado asignado.

Esto resuelve de forma completa nuestra aplicación, espero que haya sido de su agrado.

 

 

 

Creación de una Aplicación en P5.Js y Socket.io – Parte 1

¿QUÉ ES LO QUE USAREMOS?

En este post vamos abordar el desarrollo de una aplicación que haga uso de p5js, socket.io y node.js. En resumen p5js tal como está en la descripción de su propia página es una librería de javascript heredera de processing que tiene como principal objetivo hacer el proceso de codificación sencillo y accesible para artistas, diseñadores y educadores. Socket.io es la librería que permite establecer una comunicación bidireccional en tiempo real entre un cliente (tu navegador) y un servidor, esto puede sonar a websockets, pero socket.io no es websockets, hace uso de el y proporciona mayores características que permiten ir más allá; finalmente como se menciona se requiere hacer uso de un servidor y para ello que mejor si hablamos de javascript que hacerlo con Nodejs que nos permite establecer una comunicación con el mismo de forma muy escalable, lo cual viene siendo tendencia en la actualidad

¿QUÉ QUEREMOS HACER?

Una cuadrícula que se renderiza y dimensiona de acuerdo al dispositivo en el que se visualice, la cuadrícula tendrá como color por defecto el blanco, posee un menú de colores en la parte inferior, tal que al seleccionar un color y luego seleccionar una celda esta celda se pinte del color que se ha seleccionado (todo esto se logra con p5JS); pero hasta aquí solo hemos logrado tener una pequeña aplicación que solo nos sirve a nosotros, la idea es que muchas personas a la vez puedan ir cambiando los colores de la cuadrícula y observar que celdas han sido cambiadas por otros en tiempo real, esto se logra a través de la comunicación entre los clientes y el servidor, el servidor despacha los cambios y los clientes ejecutan los cambios al instante (esto se logra a través de socket.io); finalmente todo ello debe tener un lado del servidor que sea el que comunique a los demás clientes lo que está sucediendo.

MANOS AL CÓDIGO EN EL BACKEND

508192_b.gif

Lo primero es iniciar al proyecto (por cierto estoy haciendo uso de VS Code), para ello en la terminal de tu editor o en la terminal de NodeJS:

npm init --yes

Luego de iniciar el proyecto, debemos de preparar la estructura de nuestra aplicación, debemos reconocer que tenemos un lado frontend y backend, en lo personal me gusta seguir la siguiente estructura:

proyecto
|->index.js
|->frontend
  |->public
     |->index.html
     |->js
     |->css
     |->img
    

Entonces nos ocupamos del backend y esto lo hacemos en el archivo index.js, ¿Qué necesitamos del servidor?, pues que esté habilitado y puesto a la escucha en un puerto específico, para habilitarlo, hemos de hacer uso de algunos módulos, cuando el servidor esté habilitado, debemos de entregarlo a socket.io para que “fluya” a través de él, entonces necesitamos primero instalar express y socket.io; express es casi el framework por defecto para trabajar con nodejs y socket.io como ya hemos mencionado es para establecer la comunicación bidireccional:

npm i express socket.io

Cuando termine de instalarse observarás que se ha creado la carpeta node_modules, carpeta en la cual han de residir las librerías en cuestión; bueno ahora en el index.js:

const express=require("express"); //requerimos al módulo
const path=require("path"); // módulo que nos permite trabajar con directorios
const IO_server=require("socket.io"); // bueno ya hemos hablado de este
const app=express(); // creamos una aplicación express

Con app hemos de implementar todo lo restante; entonces, debemos de informar a nuestra aplicación que hemos de usar archivos estáticos (podemos decir que los archivos estáticos son aquellos que solo se cargan una vez y son inmutables) para ello express hace uso del método estático (valga la redundancia) static:

app.use(express.static(path.join(__dirname,"frontend/public")));

El método static recibe como parámetro una dirección de tipo String en donde se encuentran los archivos estáticos, pero esta dirección debe ser indicada desde el mismo sistema, pero dado que el sistema de nuestro servidor puede ser windows o linux, colocar la dirección en crudo puede ser considerado como hard-codeo, en consecuencia usamos la propiedad __dirname  de nodejs y lo unimos con la carpeta frontend/public donde están nuestros archivos, esta unión se realiza con el método join del módulo path.

Ahora que hemos indicado nuestros archivos estáticos debemos de poner nuestro servidor a la escucha:

let servidor=app.listen(process.env.PORT || 3000,()=>{
    console.log("Estamos en línea");
})

Para ello usamos el método listen, este método recibe como parámetro opcional  el puerto, pues si no se indica será el sistema quien asigne un puerto, ahora bien, dentro de dicho parámetro hemos hecho uso de la propiedad process.env.PORT nos permite acceder al puerto del entorno del usuario, cuestión muy útil cuando subamos nuestra aplicación a entornos como heroku por ejemplo; el segundo parámetro es un callback que podemos usar en su forma más básica para notificar que el servidor está en funcionamiento, este servidor a la escucha lo entregamos a una variable “servidor“.

Hasta este punto ya no tenemos nada más que hacer con express, ahora debemos de configurar lo relacionado a socket.io, ¿Qué ocurre aquí?, socket.io necesita ser unido a un servidor y asignarlo a una variable que ha de gestionar todo lo relacionado a él:

const io=IO_server(servidor);

Hecho esto, hay que entender una dinámica básica en socket.io, un servidor o cliente puede estar a la escucha de eventos y al mismo tiempo puede emitirlos, es ahí que podemos decir que es bidireccional, para implementar la escucha y emisión de un evento hacemos uso de los métodos on y emit los cuáles registran los eventos que han de funcionar de forma bidireccional; sin embargo, el primer evento que se debe registrar es cuando se establece una conexión; es decir que estaremos a la escucha usando on, este evento es conocido como “connection“, si observamos el constructor del método on, este escucha el evento y hace el tratamiento a través de un callback, el callback recibe como parámetro un socket, el cual luego del evento connection es quién ha de distribuir los eventos entre los clientes:

io.on("connection",(socket)=>{
    console.log("Conexión extablecida",socket.id);
})

Recordemos que en el lado del backend socket.io ha de estar recibiendo y reenviando los eventos sucedidos entre los clientes, y esto lo logrará a través del socket que ha recibido al establecerse una comunicación con un cliente; entonces, vamos a registrar dos eventos, el primero será estando a la escucha de un evento al que llamaremos “dibujar” el cual se generará cuando en un cliente pinte un cuadrado, cuando esto suceda, debemos de saber dos cosas la posición x,y del cuadrado que ha sido pintado y el color con el cual ha sido pintado, estos datos los recibiremos como parámetros, y lo emitiremos a los demás, con una pequeña particularidad, cuando emitamos el evento debemos asegurarnos que lo emitimos a todos menos al mismo cliente que genero el evento, pues no tiene sentido notificarle a él del evento siendo él quién lo generó, este evento que emitimos, lo realizamos con el método emit, emit recibe como parámetro un registro de evento (al que llamaremos “redibujar“) y los datos a enviar:

io.on("connection",(socket)=>{
    console.log("Conexión extablecida",socket.id);
    socket.on("dibujar",(datos)=>{
        console.log(datos);
        socket.broadcast.emit("redibujar",datos);
    })

})

Un detalle que agregar, para asegurar que el evento que el cliente ha generado no se le comunique a el mismo pero sí a los demás, usamos el modificador broadcast. Muy bien, esto es todo lo que debemos de hacer en nuestro fichero index.js; ahora debemos de pasar al frontend.

MANOS AL CÓDIGO EN EL FRONTEND

Ahora debemos de abordar la parte visual de nuestra aplicación, para ello creamos el fichero main.js y cuadrados.js dentro de la carpeta js y pasamos hacia el fichero index.html, en index.html debemos de colocar las librerías de p5js y p5.dom.js para ello usaremos sus CDN, también el fichero cuadrado.js y main.js; creamos una tag “main” y asignamos como id=”juego”:

1

¿Qué otra cuestión particular notamos? pues la dirección:

src="/socket.io/socket.io.js"

Este script es otorgado por socket.io desde el backend.

Esto es todo lo que haremos respecto al index.html; ahora vamos al fichero cuadrados.js.

En cuadrados.js hemos de crear la clase de cuadrados que han de conformar la grilla, tendrá como constructor la posición x e y, el ancho, el alto, la fila y columna a la que pertenecen y un valor opcional de tipo objeto referido al color; esta clase solo tendrá un método que será dibujarCuadrado(), valga la redundancia que lo que hará será dibujar un cuadrado; entonces:

class Cuadrados{
    constructor(x,y,w_c,h_c,fila,columna,mi_color={r:255,g:255,b:255}){
        this.x=x;
        this.y=y;
        this.w_c=w_c;
        this.h_c=h_c;
        //colores
        this.id=columna + 10*fila;
        this.mi_color=mi_color;
    }

    dibujarCuadrado(){
        rectMode(CENTER)
        stroke(0);
        fill(this.mi_color.r,this.mi_color.g,this.mi_color.b);
        rect(this.x,this.y,this.w_c,this.h_c);
    }
}

La clase posee sus propiedades, las cuáles serán empleadas por el método, bien, observemos un poco el método, P5Js posee formas primitivas, entre ellas se encuentran los cuadriláteros que se definen con la función rect que recibe como parámetros, la posición X e Y, ancho y alto; pero rect solo dibuja el cuadrado, recordemos que deseamos que el color por defecto sea blanco, esto se logra con la función fill() que puede recibir una configuración RGB o un valor entre 0 a 255 si queremos que esté solo en la escala de grises, si fill se encarga de pintar el cuadrado, no podemos obviar la línea que dibuja el cuadrado, y esto si pinta con la función stroke(), stroke posee la misma configuración de color que fill. Cuando se dibuja un cuadrado, el origen x,y está situado en la esquina superior izquierda; sin embargo, para métodos de cálculo posterior debemos de hacer que su origen se sitúe en el centro del cuadrado y es por ello que usamos el atributo rectMode(CENTER), esto es todo cuánto a la descripción de las sentencias dentro del método. Ahora debemos pasar al fichero main.js pero esto lo abordaremos en una posterior publicación

Java desde Cero – Constantes – uso de Final y Static

INTRODUCCIÓN

En anteriores oportunidades hemos entendido el que una variable se declara por el tipo de dato sea primitivo o de referencia y su respectiva inicialización, esto surge a la inexorable necesidad de todo lenguaje de programación de almacenar y manipular información, para ello estos datos se almacenan temporalmente en la memoria del ordenador, las variables no son más que “nombres” que “apuntan” a una determinada parte de la memoria y que es usada para leer y escribir de forma controlada. El acceso a esta información se puede mejorar dependiendo del tipo de información que almacenemos. Por ejemplo, no es lo mismo tener la necesidad de manejar números, que letras o conjuntos de datos; aunque al final todo son ceros y unos dentro de la memoria, es la forma de interpretarlos lo que marca la diferencia, tanto al almacenarlos como al recuperarlos.

Ahora bien, tan igual que existen las variables, también existen las constantes en Java, podemos definir una constante como un valor propio de la clase que es inmutable; por ejemplo si tratásemos con el número PI. PI es una constante matemática empleada para diversos tipos de operaciones, las más resaltantes en el uso geométrico para la determinación del área y longitud de una circunferencia por ejemplo; entonces, vamos a crear dos métodos que nos permitan determinar el área y la longitud de una circunferencia

class Circunferencia{
  private double PI;
  public Circunferencia(){
      PI=3.14;
  }

  public double area(doubleradio){
      double area=PI*Math.pow(radio,2);
      return area;
  }

  public double longitud(doubleradio){
      double longitud=PI*2*radio;
      return longitud;
  }

  /**
  * @return the pI
  */

  public double getPI(){
      return PI;
  }

}

Si observamos no tiene nada de particular, PI es una variable que puede ser accesada a través de su getter, esto no es una constante, solo una variable que ha sido ya inicializada ¿verdad?, ¿Qué ocurre además?, como hemos mencionado el hecho que sea una variable hace que cuando se instancie un objeto de la clase se cree un espacio en memoria para la variable PI tantas veces como objetos de la clase podamos crear, lo cual al ser una constante resulta realmente ineficiente

¿CÓMO SE DECLARA UNA CONSTANTE?

En java declarar una constante requiere del uso de la palabra reservada “final”, podemos hacer entonces:

private final double PI=3.14;

En este contexto indica que una variable es de tipo constante, no admitirá cambios luego de su declaración y asignación de valor; final determina que un atributo no puede ser sobreescrito o redefinido. Toda constante declarada con “final” ha de ser inicializada en la misma linea que es declarada; solo por aclaración “final” también puede ser usada en otro contexto para indicar que una clase no puede tener clases que la hereden. Una de las practicas comunes al declarar una constante es usar letras mayúsculas y en la cabecera de la clase antes del constructor de la clase.

USO DE STATIC EN CONSTANTES

Revisemos algo, cuando queremos crear una constante estamos decidiendo que dicho valor será usado por todos los objetos de la clase y será inmutable, ¿Qué sucede si solo usamos final?, es cierto que hemos creado una constante, pero en cada instancia, se creará una constante por cada objeto que se vaya a crear volviendo nuevamente a una asignación de espacio en memoria por instancia, lo cual, nuevamente no tiene mucho sentido, nosotros debemos asegurar que sea inmutable y que sea una única asignación que sea compartida por todos los objetos de la clase, aquí debemos de enfatizar en algo, los atributos miembros de una clase pueden ser atributos de clase o atributos de instancia; se dice que son atributos de clase si se usa la palabra reservada “static“, en ese caso la variable única para todas las instancias de la clase ocupa un único lugar en memoria, entonces:

public static final double PI=3.14;

Hemos cambiado su modificador de acceso, ya que toda constante, variable o método que se le asigne “static” ahora podrá ser llamado directamente haciendo uso de la clase:

System.out.println(Circunferencia.PI);

USO DE STATIC EN MÉTODOS

Tal como hemos mencionado la palabra reservada static también es aplicable a un método, la particularidad de asignar static a un método:

  • Hace que el método solo pueda acceder a datos static.
  • Un método static puede llamar solo a otros métodos static.
  • Un método static se puede acceder directamente por el nombre de la clase y no se necesita crear un objeto para acceder al método (aunque si es posible como en las variables).
  • Un método static no puede hacer referencia a “this” o “super“.

Nuestro método de longitud lo convertimos a estático:

public static double longitud(double radio){
  double longitud=PI*2*radio;
  return longitud;

}

Ahora podemos invocarlos directamente con la clase sin necesidad de instanciar un objeto.

System.out.println(Circunferencia.longitud((5)));

Aquí observamos el uso de static en métodos.

Java desde Cero – POO – Construcción de Objetos

INTRODUCCIÓN

Anteriormente ya hemos tocado con relativa ligereza todo lo relacionado al paradigma de la programación orientada a objetos (POO), finalmente observamos los getters y setters como una buena práctica para acceder y configurar variables que consideremos que no deban estar expuestas directamente al usuario, es cierto que se puede crear un método que pueda comportarse como setter y getter pero ello no es recomendado como una buena práctica.

CASO

Vamos a realizar un caso práctico para observar el uso de la construcción de objetos, vamos a crear una clase “Alumno“, el cual tiene como característica que tiene un nombre, paga una pensión, tiene una fecha de ingreso y le crearemos un método que sea subir pensión, entonces manos a la obra, para crear una clase recordemos que debemos de usar la palabra reservada class y además de ello hemos de crear un constructor, la caracaterística principal del constructor es que sea public y que tenga el mismo nombre que el de la clase, este constructor ha de recibir parámetros, los parámetros son nombre, pensión, año de ingreso, mes de ingreso y día de ingreso, estos parámetros serán de tipo String, double int, int, e int respectivamente. Estos parámetros tendrán sus correspondientes propiedades de la clase, es decir existirá una propiedad nombre que ha de recibir el parámetro nombre, debemos de distinguir la propiedad del parámetro a través del uso de la palabra reservada this, aunque el único diferente será lo referido al ingreso, para ello haremos uso de la clase  LocalDate que nos permite configurar una fecha a través de uno de sus métodos (of que es de tipo estático el cual trataremos más adelante) entonces:

package clases.Alumnos;

import java.time.LocalDate;

/**
* Alumno
*/

public class Alumno {

 private String nombre;
 private LocalDate ingreso;
 private double pension;

 public Alumno(String nombre,double pension,int anio,int mes,int dia){

   this.nombre=nombre;
   this.pension=pension;
   this.ingreso=LocalDate.of(anio, mes, dia);

 }

}

Nota que hemos importado el paquete java.time el cual es parte de las implementaciones del JDK 1.8 (aquí encontrarás más sobre  of) Hemos declarado las propiedades y en el constructor las hemos definido a través de los parámetros.  Ahora debemos de crear los métodos setters y getters que nos permitan configurar y acceder a las propiedades de tipo private, ¿Pero de que propiedades necesitamos?, en líneas generales debes acceder a todas las propiedades; sin embargo, solo necesitamos poder setear la que corresponde a la pensión, es entonces que solo a pensión se le crea un método setter:

public String getNombre(){
  return nombre;
}

public LocalDate getIngreso(){
  return ingreso;
}

public double getPension(){
  return pension;
}

public void setPension(double porcentaje){
  this.pension= this.pension*(1+(porcentaje/100));
}

Note la siguiente particularidad, en setPension(), recibimos como parámetro un porcentaje con el cual se realiza el cálculo de la nueva pensión en función de ese porcentaje y se agrega a la pensión.  Hemos terminado de configurar nuestra clase Alumno, ahora podemos crear una clase cualquiera (Principal en mi caso) donde contenga el método main, e instanciamos  un objeto de la clase Alumno:

package clases.Alumnos;

/**
* Principal
*/

public class Principal {

  public static void main(String[] args){

     Alumno alumno1=new Alumno("Henry Medina",750,2016,02,12);
  }

}

Sin embargo, hacerlo de esta forma sería muy tediosa si en caso tuviéramos muchos alumnos, podemos hacerlo quizá a través del uso de los “Arrays” , entonces vamos a crear una array de nombres, pensiones, y fechas:

publicstaticvoidmain(String[]args){

  String[] nombres={"Henry Medina","Emily Fernandez","Cecilia Panebra"};
  double[] pensiones={750,850,1200};
  String[] fechas={"2016/02/12","2015/12/01","2017/03/15"};
  Alumno[] alumnos=new Alumno[3];

  for(int i =0; i < nombres.length; i++){
    String[] partes=fechas[i].split("/");
    alumnos[i]=new Alumno(nombres[i], pensiones[i], Integer.parseInt(partes[0]), Integer.parseInt(partes[1]), Integer.parseInt(partes[2]));
 }

  for(Alumno alumno : alumnos){
   System.out.println(alumno.getNombre()+" tiene una pensión de: "+alumno.getPension()+" e ingreso en fecha: "+alumno.getIngreso());

 }

}

Los arrays de los nombres y pensiones no tienen complicación, nótese que las fechas son introducidas como si de un string se tratase, hemos creado el arreglo de alumnos que está conformado por instancias de la clase Alumno; sin embargo, aún no los hemos inicializado, para ello vamos hacer uso del bucle for, ¿Qué es lo primero que hacemos en el bucle?, recuerdese que el constructor de Alumno, pide el año, mes y el día como enteros y nosotros solo estamos recibiendo un string; entonces, el primer paso consiste en obtener de cada fecha su año, mes y su día y lo almacenamos en un arreglo que hemos llamado partes, para lograr ello usamos el método split el cual requiere como parámetro que se indique el caracter separador (“/”), entonces tendremos que partes será para la primera fecha será:

partes={"2016","02","12"}

Hecho esto llamamos a la posición i del arreglo alumno (i va desde el 0 hasta el 2) he inicializamos las instancias, asignando de igual forma el nombre y pensión en la posición i, cuando tenemos que introducir la fecha tenemos que asignar las posiciones del arreglo partes; sin embargo, estos son strings, para ello debemos parsear o castear desde un tipo string a un tipo int, esto lo logramos con el método estático parseInt(String x) que pertenece a la clase Integer y que recibe como parámetro un String, es por ello que cada elemento es parseado y entregado al constructor:

Integer.parseInt(partes[0])

Hecho esto, procedemos luego a imprimir cada uno de los resultados, para ello usamos el bucle for each, ¿Qué de particular notamos?, pues que estamos accediendo a las propiedades no directamente (ya que están encapsuladas) sino a través de su respectivo método getter. Ahora vamos hacer uso del método setPension(), lo podríamos hacer agregando al bucle foreach el método, es decir:

for(Alumno alumno : alumnos){
    alumno.setPension(5);
    System.out.println(alumno.getNombre()+" tiene una pensión de: "+alumno.getPension()+" e ingreso en fecha: "+alumno.getIngreso());
}

Verás que los valores impresos han sido aumentados en un 5%, este ha sido un ejemplo en el cual hemos usado casi todo lo que hemos aprendido hasta el momento, saludos.

Java desde Cero – Programación Orientada a Objetos 2

INTRODUCCIÓN

Anteriormente ya hemos revisado el paradigma de la programación orientada a objetos (POO), que en resumen es el modelado del programa como si fueran objetos de la vida real;  también observamos que el agrupamiento de las características comunes en los objetos se hace a través de las clases, así también explicamos el concepto de modularización como parte de una buena práctica para concentrar segmentos de código que nos permitan un funcionamiento limpio y sencillo para el tratamiento de errores; finalmente observamos el encapsulamiento que es la restricción de ciertas propiedades que no deben ser visibles al usuario, razones miles por las cuáles no deseamos que lo sean, pero ¿Cómo podemos acceder a ellas?, en este post haremos un tratamiento al respecto.

La programación orientada a objetos, no nos debe permitir modificar las propiedades de una clase a no ser que sea a través del canal correspondiente, el canal correspondiente se realiza a través de los métodos, específicamente a través de los métodos getter o setter, antes de ello debemos definir que es un método.

MÉTODOS

Por el principio de modularidad un problema complejo debe ser subdividido en subproblemas (problemas más sencillos) y así sucesivamente hasta que los problemas más pequeños sean sencillos de resolver, esto es conocido como diseño descendente (top-down design) y se denomina descendente porque empieza en la parte superior.

metodo

Los subalgoritmos pueden entenderse como subprogramas para resolver un aspecto específico del gran problema, a este tipo de subprogramas se le denomina método o función. Matemáticamente una función, es una operación que toma uno o más valores llamados argumentos y produce un valor denominada resultado, Java como hemos observado tiene funciones (métodos) predeterminados:

Math.pow()
Math.sqrt()
System.out.println()

Sin embargo, el usuario también puede definir sus propias funciones, por ejemplo:

metodo2

 Donde f es el nombre de la función y x es el argumento. Obsérvese que ningún valor específico se asocia con x, es un parámetro formal utilizado en la definición de la función.  Para evaluar f debemos de darle un valor real a x, por ejemplo si x=3 f será 0.3. En java un método sigue la siguiente sintaxis:

[Modificador_de_acceso] tipo_de_dato Nombre ([parámetros])[throws lista_excepciones]{
          sentencias
          [return resultado]
}
  • Modificador de acceso [opcional]: Determinan el tipo de acceso al método (private, public, etc).
  • Tipo de dato: Indica el tipo del valor que devuelve el método. En java es imprescindible que en la declaración de un método se indique el tipo de dato que ha de devolver. El dato se devuelve mediante la instrucción return. Si el método no devuelve ningún valor este tipo será void.
  • Nombre: Es el nombre que se le da al método. Para crearlo hay que seguir las mismas normas que para crear nombres de variables.
  • Parámetros [opcional]: Después del nombre del método y siempre entre paréntesis puede aparecer una lista de parámetros (también conocidos como argumentos) separados por comas. Estos parámetros son los datos de entrada que recibe el método para operar con ellos, un método puede recibir cero o más argumentos, por cada parámetro que se introduzca se debe indicar su tipo como si declarásemos una variable.
  • Throws lista de Excepciones [opcional]: Indica las excepciones que puede generar y manipular el método, este desarrollo lo veremos más adelante.
  • return [opcional]: Se utiliza para devolver un valor. La palabra return va seguida de una expresión que será evaluada para saber el valor del retorno. Esta expresión puede ser compleja o puede ser simplemente el nombre de un objeto, una variable de tipo primitivo o una constante. El tipo de valor de retorno debe coincidir con el tipo de dato declarado en el método. Si el método no devuelve nada entonces el tipo de dato será void y la instrucción return se volverá opcional. El inicio y fin de un método se da entre las llaves { }.

Aquí algunos ejemplos:

private void correr(int velocidad){
  System.out.println("Hola la velocidad es: " + velocidad);

}

public double calculo_velocidad(int distancia,int tiempo){
  double velocidad=distancia/tiempo;
  return velocidad;
}

SETTERS Y GETTERS

Tal como hemos mencionado encapsular un atributo o método significa restringir su uso a otras instancias de la clase y que solo pueden ser modificadas dentro de la clase misma donde fueron creadas, se estila su uso para proteger características propias del constructor de la clase o de métodos que no deben ser alterados porque son de uso común; sin embargo, si bien es cierto que se deben proteger también deben de existir mecanismos que nos permitan tener acceso a dichos atributos, y en el encapsulamiento los métodos adecuados son los métodos  setter y getter. Un método setter define el valor de la propiedad y un getter obtiene el valor de una propiedad, existen convenciones sobre su implementación:

Método Getter:

public tipo get+nombre_variable(){
   return variable
}

public double getAlto() {
   return alto;
}

Como puede observarse el método getter inicia con un modificador de acceso public, esto es pues debe ser accesible desde otras clases, no tendría sentido si no lo fuera, luego debe indicar el tipo que ha de devolver (eso ya se ha explicado líneas arriba), definido el tipo debe colocar  la palabra get como un prefijo más el nombre de la variable que hace referencia, lo demás sigue la misma estructura de un método, get es una convención que permite a otros programadores que observen tu código entender que haces referencia a un método getter.

Método Setter:

public void set+nombre_variable(parámetro){
   this.nombre_variable=parámetro
}

public void setAlto(double alto) {
  this.alto= alto;
}

Nuevamente el modificador de acceso es public ya que estará accesible desde otras clases, usar el tipo void, lo que como ya hemos definido significa que no devuelve valor alguno y el return no se coloca; sin embargo, lo nuevo es que ahora el método recibe un parámetro, el parámetro debe ser del mismo tipo de la propiedad que ha de modificar; otro aspecto es el uso de la palabra reservada this. Aunque su aplicación es mayor, this, nos permite realizar una referencia al objeto asociado, por ejemplo si el parámetro recibido le hemos asignado el nombre de “alto” y tenemos una propiedad “alto“, hacer this.alto indica que se está haciendo referencia a una propiedad del objeto y no al parámetro, si colocáramos simplemente alto java entendería que solo estamos haciendo referencia al parámetro.

 

Java desde Cero – Programación Orientada a Objetos 1

INTRODUCCIÓN

Java es un lenguaje de programación orientado a objetos (POP), POO es un paradigma de la programación actualmente vigente, básicamente consiste en dar a los elementos que componen un programa el comportamiento y propiedades que tienen los objetos en la vida real y dado que ya estamos familiarizados con el trato de los objetos del mundo real en el día a día, establecer una relación hacia la programación de software debía ser más sencillo o comprensible. No se trata de nuevas características sino de una NUEVA FORMA DE PENSAR viendo a la programación y su composición como observamos a los objetos en la vida real.

¿QUÉ OBSERVAMOS EN LOS OBJETOS?

Los objetos tienen un estado, un comportamiento ( también conocido como capacidades, cosas que pueden hacer) y propiedades. Por ejemplo pensemos en un Televisor (no importa la marca):

televisor-samsung-43-smart-tv-full-hd-serie-5-un43j5200dkxzl.jpg

¿Qué estado puede tener?

  • Prendido o apagado, quizá en algunos, suspendido

¿Qué propiedades podemos observar?:

  • Tiene un ancho, alto y grosor, color, parlantes, soporte, etc.

¿Qué comportamientos o capacidades?, ¿Qué cosas puede hacer?

  • Prender, apagar, manipular el volumen de sonido, etc.

¿CÓMO BENEFICIA O EXPRESA EN LA PROGRAMACIÓN ESTE PARADIGMA ORIENTADO A OBJETOS?

El programa puede  dividirse en partes (modularización)   y agruparse en función de clases que permitan su identificación y reutilización (Herencia), algunas de esas agrupaciones no están expuestas al usuario a simple vista (encapsulamiento) (como los circuitos del televisor para que no se haga daño el usuario);  de forma más sencilla, tiene entre otras ventajas que el mal funcionamiento de un módulo (por el momento un segmento del código) no implica la caída total del programa, tan igual que sucede en la vida real, si una parte de la pantalla se estropea no implica que todo el televisor deje de funcionar (obviamente se verá mal, pero el funcionamiento proseguirá), y así también nos permite hacer el tratamiento del mismo, ocurre de forma similar en el software a través del manejo de las Excepciones.

CLASES

¿Qué es una clase?, podemos decir que una clase es una plantilla o modelo que definen las características y métodos (funciones que están dentro de una clase)  comunes a un grupo de objetos. Cuando se define una clase, se declara su forma y naturaleza de forma exacta; para hacerlo más comprensible vamos a tratar objetos de la vida real, pensemos en bicicletas:

mens-roadster-negro-1

Pensar en una bicicleta  y sus componentes en términos generales es saber que tiene: 2 ruedas, frenos, cadena, silla, tubos, pedal, timón, etc (no uso bicicletas). Podemos decir que estos componentes son las características comunes a todas las bicicletas; sin embargo, incluso las bicicletas a través de estas características comunes poseen una medida de estas características, como por ejemplo el color de los tubos, las dimensiones de las ruedas, el material que las compone, etc. También tienen una serie de comportamientos (cosas que pueden hacer que también conocidos como métodos):

2022185043700_2

 

plegable-fabric

Si las clases son los modelos de las características y métodos que poseen en común un conjunto de objetos, podemos decir entonces que un objeto es la representación o instancia de una clase.

Llevemos todo esto a código:

En Java una clase se expresa a través de la palabra reservada Class, se estila que el nombre de la clase inicie con mayúsculas y que tenga el mismo nombre que tiene el archivo, entonces si creamos un archivo Bicicleta.java debemos de crear nuestra primera clase como:

public class Bicicleta {
 int ruedas;
 int asientos;
 double largo;
 double alto;
 String color;
 String material;
 int peso;
}

Nota que tenemos  otra palabra reservada denominada public, por el momento no le tomes atención pero te adelanto que pertenece a los modificadores de acceso; entonces dentro de la clase hemos definido las propiedades de la clase bicicleta, pero aún no le hemos dado un estado inicial (inicializado), para inicializar estas propiedades debemos de hacer uso de otro componente de la clase que se denomina el constructor. El constructor es un método especial de una clase que se llama automáticamente siempre que se declara una instancia (objeto) de la clase, ya que cuando se crea un objeto en Java se realizan las siguientes operaciones:

  • Se asigna memoria para el objeto.
  • Se inicializan los atributos de ese objeto con los valores predeterminados del sistema.
  • Se llama al constructor de la clase que pueden ser uno o varios.

¿Cómo se reconoce a un constructor?, pues debe llevar el mismo nombre de la clase y el uso de la palabra reservada public. Veamos como se expresa en código:

class Bicicleta {
    int ruedas;
    int asientos;
    double largo;
    double alto;
    String color;
    String material;
    int peso;

  public Bicicleta(){

      ruedas=2;
      asientos=1;
      largo=1.5;
      alto=0.5;
      color="Amarillo";
      material="Azul";
      peso=20;

  }

}

Ahora, ¿Cómo hacemos uso de las clases?, pues a través de sus instancias, entonces debemos de instanciar una clase el cual es un ejemplar de clase u objeto. Para instanciar una clase debemos de hacerlo de la siguiente forma:

Bicicleta clasica=newBicicleta();

Tal como puedes observar, es casi similar a declarar un tipo primitivo, ya que debemos de declarar el tipo, en este caso del tipo Bicicleta, seguido un nombre y  la palabra reservada new. A partir de ello, el objeto clasica, puede hacer uso de las propiedades de la clases o sus métodos, para que puede acceder a cualquiera de ellos se utiliza la nomenclatura del punto que se traduce en:

objeto.propiedad  u objeto.metodo

 

Por ejemplo para acceder a las ruedas de nuestra bicicleta podemos hacer:

clasica.ruedas;

MODULARIZACIÓN 

El ejemplo más común es hacer uso de un equipo de sonido:

modulo1.png

Un equipo de sonido está compuesto, de su lector de CD, su radio, su casetera (modelos más antiguos) y lector de usb; cada uno de los elementos descritos es un todo en si mismo (también se les conoce como clases) que al unirse componen un elemento más complejo que funciona en armonía  (lo que es el equipo de sonido modular), si ocurriese que alguno de estos elementos se averíe, el equipo de sonido seguiría en funcionamiento, podemos decir que estos elementos son módulos del equipo de sonido  y que el mal funcionamiento de un módulo implique que el equipo de sonido deje de funcionar en su totalidad; esto pasa de similar forma en la programación, la modularización segmenta el programa en partes que han de funcionar en armonía siendo su principal ventaja la depuración de errores y reutilización de código ya que se encuentran más focalizados, En JAVA como en todo lenguaje orientado a objetos sucede de igual forma, entonces un programa en Java es un grupo de clases (módulos, funciones o métodos) unidos entre sí y que funcionan como una unidad. Esto se expresa en Java a través del uso de archivos donde se estila que exista solo una clase, un fichero, una clase, esto permite que todo sea más ordenado y se hace uso como una buena práctica, pero también se expresa en crea rutinas re-utilizables dentro de nuestro programa, esto se logra construyendo métodos lo más genéricos posibles de forma que podamos utilizarlos en diferentes instancias de nuestro programa e inclusive utilizarlos en otros programas, reduciendo de esta manera la cantidad de líneas de código que tenemos que escribir, pero no todo es color de rosa.

ENCAPSULAMIENTO

Siguiendo con el ejemplo de equipo de sonido, vemos que funcionan en armonía como un todo, el volumen, puede aumentar el volumen de todo el equipo, pero no puede dar salto hacia otra canción que se encuentre en la lectora de CD, y en viceversa, la lectora de CD no puede subir o bajar el volumen, y ¿Por qué no? pues porque no tendría sentido, bajar o subir el volumen, adelantar una canción o retroceder una desde otro módulo, solo puede hacerse desde su mismo módulo; de similar forma pasa con la programación, imaginemos que en una clase cualquiera instanciamos la clase Bicicletas, ya que hasta el momento no está encapsulada alguna de sus propiedades un usuario cualquiera podría sobrescribir la propiedad rueda diciendo que ahora son 5:

clasica.ruedas=5;

Tan simple como la línea anterior, dado que esto resulta ilógico, también resulta inseguro que el usuario pueda modificar algunas propiedades de forma directa. Para ello debemos de agregar un modificador de acceso de tipo private (más adelante hablaremos de ello), agregando dicho modificador de acceso dicha propiedad es accesible desde la clase pero no desde otra clase. Entonces:

class Bicicleta {
  private int ruedas;
  private int asientos;
  private double largo;
  private double alto;
  String color;
  String material;
  private int peso;

  publicBicicleta(){
    ruedas=2;
    asientos=1;
    largo=1.5;
    alto=0.5;
    color="Amarillo";
    material="Acero";
    peso=20;

  }

}

Hemos colocado el modificador de acceso private solo a aquellos elementos que no deban ser modificables por el usuario, el usuario podrá modificar el color, pero no la cantidad de asientos o ruedas que tenga una bicicleta; pero ¿Cómo podemos tener acceso a estas propiedades?, para ello existen métodos que son como los cables que unen los módulos del equipo de sonido; sin embargo, trataremos esos tópicos en una próxima oportunidad pues este post ya se está extendiendo demasiado.