Bienvenidos sean a este post, hace un par de posts atras hablamos sobre la programacion orientada a objetos donde mencionamos varios temas y entre ellos la encapsulacion y hoy nos centraremos en este tema.
Nosotros en ese post mencionamos de forma muy basica en que consiste la encapsulacion y cuales son los beneficios de su uso pero en que nos puede ayudar realmente? Esta forma de trabajar nos previene de cometer errores a la hora de trabajar con nuestras clases, por ejemplo puede ocurrir lo siguiente:
brown.salud = 100
cabral.tipoSoldado = "marino";
brown.fuerzaBrazo = 100;
cabral.salud = 150;
cabral.tipoSoldado = "payaso";
cabral.fuerzaBrazo = -100;
En este caso agregamos una nueva variable llamada fuerzaBrazo para indicar el nivel de fuerza de ataque de nuestro soldado, en el primer caso no hubo inconvenientes pero en el segundo caso no solamente pudimos poner cualquier tipo sino que tambien por un error de tipeo le arrancamos los brazos a nuestro soldado 😱, esto puede ocasionar incluso errores de ejecucion en nuestro juego y para evitar esto entra en accion la encapsulacion, y mas exactamente los modificadores de acceso.
Si bien no lo hemos explicado si lo hemos mencionado o mostrado en varias oportunidades, por ejemplo:
public class MainActivity extends Activity {
En este caso usamos el modificador public y tambien lo hemos usado sin ninguno el cual equivale a default, veamos la siguiente tabla con los modificadores de acceso disponibles:
- default, es cuando no informamos ningun modificador y este restringe el acceso a la clase de manera externa
- public, es el modificador que concede los permisos de acceso para todas las clases y otros elementos de la misma
- protected, este al igual que default permite el uso interno, tambien concede acceso a la clase heredera de esta pero restringue a los externos
- private, este restringe completamente el acceso de manera externa
Estos modificadores tambien aplican a las variables y funciones de las clases internamente, las mas usadas en general seran public para conceder permisos totales a los elementos o private para restringir el acceso total, y tanto default como protected son utilizados de manera muy particular porque el primero es muy similar al private, en general siempre se considera que cuando no se informa modificador el lenguaje opta por private, y el segundo (protected) restringe a los objetos que se crean de la clase pero las clases herederas de esta tendran acceso de tipo public a la misma, mas adelante veremos algun ejemplo de como nos beneficia este tipo de acceso.
Por ejemplo tomemos de nuevo a la clase Soldado, modifiquemos algunos elementos:
public class Soldado {
private int salud;
private String tipoSoldado;
public void disparar(){
Log.d(tipoSoldado,"esta disparando!");
}
}
En este caso por ejemplo restringimos el acceso a las variables, es decir que si volvemos a probar nuestra aplicacion anterior nos devolvera un error porque ahora no podemos modificar los valores de las variables, en cambio ahora disparar si puede ser accedida desde cualquier lado pero ahora perdimos el acceso a las variables y como lo retomamos? Aca entra en accion Getter and Setter.
Los metodos Getter and Setter son dos funciones para obtener la informacion (get) y otro para establecer la informacion (set), vamos a tomar la clase anterior y lo modificaremos de la siguiente manera:
package org.example.clasesbasicas;
import android.util.Log;
public class Soldado {
private int salud;
private String tipoSoldado;
public void setSalud(int s){
salud = s;
}
public int getSalud(){
return salud;
}
public void setTipoSoldado(String t){
tipoSoldado = t;
}
public String getTipoSoldado(){
return tipoSoldado;
}
public void disparar(){
Log.d(tipoSoldado,"esta disparando!");
}
}
Nota: Getter and Setter es una nomenclatura establecida por convencion para indicar que utilizaremos metodos para establecer y recuperar informacion pero no necesariamente se debe usar set y get, tambien podremos usar otros nombres pero es mas practico indicarlos de esta manera.
En este caso podemos ver como agregamos cuatro metodos para establecer y recuperar la informacion de las variables, en ambos casos de set usamos el tipo void y en los argumentos recibimos un valor del mismo tipo de la variable, luego en el bloque asignamos el valor recibido a la variable, en este caso funciona porque recuerden que private restringe al externo no al interno, a los metodos get no le enviamos informacion pero son del mismo tipo al que debemos recuperar, en el bloque usamos a return para devolver el valor de las variables, con estos metodos podemos tener acceso a las variables, por ejemplo podemos crear otra clase dentro de la clase Principal para ello agregaremos el siguiente bloque por dentro de la clase RTSActivity:
class Hospital
{
private void curarSoldado(Soldado soldado){
int salud = soldado.getSalud();
salud += 10;
soldado.setSalud(salud);
}
}
En este caso tenemos una nueva clase llamada Hospital la cual, en realidad es como una sub clase, tendra un metodo de tipo privado llamado curarSoldado, el cual recibe como argumento a nuestro soldado, esto nos permitira curarlo no importa quien sea, crearemos una variable llamada salud de forma local y por medio de getSalud le asignaremos el valor de nuestro soldado, luego tomaremos ese valor y lo incrementaremos en 10 para despues asignar el nuevo valor a traves de setSalud, con esto ya tenemos un Hospital para nuestros soldados.
Para nuestra siguiente modificacion trabajaremos sobre el metodo onCreate y lo cambiaremos de la siguiente manera:
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Soldado brown = new Soldado();
Soldado chamame = new Soldado();
Soldado cabral = new Soldado();
Hospital hospital = new Hospital();
brown.setSalud(100);
brown.setTipoSoldado("marino");
chamame.setSalud(110);
chamame.setTipoSoldado("piloto");
cabral.setSalud(150);
cabral.setTipoSoldado("soldado");
Log.d("Salud de Brown = ", "" + brown.getSalud());
Log.d("Salud de Chamame = ", "" + chamame.getSalud());
Log.d("Salud de Cabral = ", "" + cabral.getSalud());
brown.disparar();
chamame.disparar();
cabral.disparar();
}
Antes de modificar el codigo si lo observaron tendrian la notificacion de varios errores, en este caso en las variables diciendo que no poseemos el acceso suficiente para las mismas, en este nuevo codigo basicamente lo que hacemos es usar a setSalud y setTipoSoldado para cada soldado y establecer los valores de las variables, luego mostraremos en el log de la aplicacion la salud de los soldados y la llamada a la funcion disparar, un ultimo detalle es que creamos un nuevo objeto llamado hospital que no esta implementado pero lo haremos ahora agregando las siguientes lineas despues de las lineas de disparar:
hospital.curarSoldado(chamame);
Log.d("Salud de Chamame = ","" + chamame.getSalud());
Con este podemos curar a nuestro soldado con los valores que queramos, luego lo mostraremos en pantalla, una curiosidades de esto ultimo:
- Esta clase tiene acceso de tipo default donde solo podra sera accedida por esta clase y los miembros de la misma
- Tenemos acceso a curarSoldado a pesar de ser privado
- Permite «curar» a nuestros soldados sin restricciones
- Anula la visibilidad de nuestros elementos lo cual nos evita errores
Si lo compilamos y tendremos una salida semejante a la siguiente:
05-19 15:44:25.828 14132-14132/? W/System: ClassLoader referenced unknown path: /data/app/org.example.clasesbasicas-1/lib/x86
05-19 15:44:25.922 14132-14132/? D/Salud de Brown =: 100
05-19 15:44:25.922 14132-14132/? D/Salud de Chamame =: 110
05-19 15:44:25.922 14132-14132/? D/Salud de Cabral =: 150
05-19 15:44:25.922 14132-14132/? D/marino: esta disparando!
05-19 15:44:25.922 14132-14132/? D/piloto: esta disparando!
05-19 15:44:25.922 14132-14132/? D/soldado: esta disparando!
05-19 15:44:25.923 14132-14132/? D/Salud de Chamame =: 120
05-19 15:44:25.981 14132-14147/? D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
Este es simplemente un extracto del log de nuestra aplicacion pero podemos ver como se incremento la variable salud, lo bueno de trabajar de esta forma es que tanto la recuperacion como la modificacion se hace a traves de funciones y nosotros podemos crear restricciones mas importantes para evitar modificaciones incorrectas, pasemos al siguiente tema como son los contructores.
Los constructores son mecanismos que nos permiten crear un espacio en memoria para nuestros objetos y estos se hacen por medio de la palabra new, un ejemplo es el siguiente:
Soldado brown = new Soldado();
El constructor siempre existe aunque no lo declaremos o definamos, a este se le denomina predeterminado y tiene la siguiente sintaxis:
public Soldado() {}
Siempre el modificador es public para poder ser accedido bajo cualquier circunstancia despues tendra el nombre de la clase seguido de los parentesis y las llaves del bloque con o sin informacion pero en general esta vacio, tal como dijimos antes si no lo declaramos el lenguaje lo hace de forma interna pero nosotros tenemos la posibilidad de crear otros constructores que puedan asignar valores y por ende al momento de construir nuestros objetos podemos asignar valores a las variables, por ejemplo vamos a modificar a la clase Soldado de la siguiente forma:
package org.example.clasesbasicas;
import android.util.Log;
public class Soldado {
private int salud;
private String tipoSoldado;
public Soldado(){}
public Soldado(int s, String t){
salud = s;
tipoSoldado = t;
}
public void setSalud(int s){
salud = s;
}
public int getSalud(){
return salud;
}
public void setTipoSoldado(String t){
tipoSoldado = t;
}
public String getTipoSoldado(){
return tipoSoldado;
}
public void disparar(){
Log.d(tipoSoldado,"esta disparando!");
}
}
En este codigo nuestra unica modificacion es el siguiente bloque:
public Soldado(){}
public Soldado(int s, String t){
salud = s;
tipoSoldado = t;
}
Primero declaramos al constructor predeterminado, el segundo constructor recibe dos valores: uno de tipo int y otro de tipo String, dentro del bloque nos encargaremos de asignar el valor de tipo int a salud y el de tipo String a tipoSoldado, el resto sigue trabajando de la misma forma, en este caso no se uso a Getter and Setter porque esta dentro de la misma clase, nuestra siguiente modificacion sera en onCreate de RTSActivity:
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Soldado brown = new Soldado(100,"marino");
Soldado chamame = new Soldado(110,"piloto");
Soldado cabral = new Soldado(150,"soldado");
Hospital hospital = new Hospital();
Log.d("Salud de Brown = ", "" + brown.getSalud());
Log.d("Salud de Chamame = ", "" + chamame.getSalud());
Log.d("Salud de Cabral = ", "" + cabral.getSalud());
brown.disparar();
chamame.disparar();
cabral.disparar();
hospital.curarSoldado(chamame);
Log.d("Salud de Chamame = ","" + chamame.getSalud());
}
En este caso al momento de crear nuestros objetos utilizaremos a nuestro nuevo constructor para que asigne los valores a la variables de nuestro objeto, lo bueno de trabajar de esta forma es que podemos pasar todos los valores que necestiemos y despues desaparecio el bloque donde asignabamos los valores a cada uno de los objetos, esto da como resultado un codigo mas compacto y mas legible, si lo compilan debe funcionar exactamente de la misma forma.
Nota: Esto que hicimos se llama sobrecarga y tambien se hace con los metodos, un constructor es un metodo, por otro lado en el constructor predeterminado podemos asignar valores a nuestras variables pero es una mejor practica dejarlo vacio y crear los constructores que necesitemos.
Nos quedan solamente dos temas, el uso del this y los metodos estaticos.
this
El this es un apuntador de memoria que se usa para tener bien referenciado a nuestro objeto, por ejemplo tomemos el constructor anterior:
public Soldado(int s, String t){
this.salud = s;
this.tipoSoldado = t;
}
En esta modificacion lo mas importante es que this sera usado para decirle que las variables de esta clase son las que debemos modificar, aunque nosotros mas adelante lo veremos con otra utilidad como es decirle al lenguaje que utilice «esta» (this) actividad seguida de la variable a la cual le asignaremos un nuevo valor o para un metodo como parametro, pero cuando hagamos otros ejemplos lo veremos de mejor forma, nuestro ultimo tema son los metodos estaticos.
static
Este modificador nos permite trabajar con clases sin necesidad de ser instanciadas porque como su nombre lo indica al ser estatico siempre van a estar disponibles para el resto de las clases, por ejemplo como hicimos hasta ahora con Log e inclusive cuando llamamos a sus variables o metodos sin necesidad de crear un objeto, por ejemplo:
bitmapBlanco = Bitmap.createBitmap(numHorPixels,
numVerPixels, Bitmap.Config.ARGB_8888);
Por ejemplo aqui tenemos una linea del proyecto Cazador de Submarinos donde tenemos un objeto llamado bitmapBlanco y a la cual utilizamos el metodo createBitmap por medio de la clase Bitmap, esto es lo que nos permite un metodo estatico, lo unico que debemos siempre informarle la clase desde donde debemos llamarla, esto es cuando incluimos los paquetes al comienzo de cada clase.
En resumen, hoy hemos visto mas a fondo la encapsulacion, como es, para que se usa, que es getter and setter, como nos permite ocultar los elementos de una clase y como nos ayuda para evitar errores, hemos visto a los modificadores y como nos ayuda en conjunto con getter and setter, tambien hemos visto como asignar informacion por medio de constructores, el uso del this y que es un metodo estatico (static), espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.
Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar
Es para mantenimiento del sitio, gracias!
$1.00