Está en la página 1de 33

Creacin de un Televisor estndar

Paso 1: Operativa
Crear la Clase Televisor
En este caso, como esta Clase no va a contener ningn mtodo main(...)

elegimos New | Java Class... en vez de New | Java Main Class...


y le damos el nombre Televisor

Este es el cdigo creado por el asistente


package paqtvestandar;
public class Televisor {
}

package paqtvestandar;
o de momento, saber que esta primera lnea es necesaria para indicar que la Clase Televisor
pertenece al paquete paqtvestandar

Aadir cdigo a la Clase Televisor


A esta Clase le vamos a aadir una variable de instancia llamada canal que va a ser de tipo int
package paqtvestandar;
public class Televisor {
int canal;
}

int canal;
o los datos o variables definidos en una clase se llaman variables de instancia o atributos , porque
cada Instancia de una Clase, es decir, cada Objeto de la Clase contiene una copia propia de estas
variables
o imaginemos una fbrica de coches que tiene un molde de un modelo de coche (una Clase) del
cual se fabrican nuevos coches (Instancias u Objetos).
 un ejemplo de variables de instancia o atributos de estos coches que estn en circulacin
(Objetos) podran ser
 la matrcula
 el nmero de bastidor
 el color
o en nuestro caso, tenemos que aadir esta lnea para indicar que la Clase Televisor tiene una
variable de instancia de tipo int que se llama canal

Compilar la Clase Televisor


Ahora vamos a crear la Clase Aplicacion.
1

Nota: Recordemos que esta Clase al tener un mtodo main(...) la vamos a tener que crear eligiendo New | Java
Main Class...
package paqtvestandar;
public class Aplicacion {
public static void main(String[] args) {
// TODO code application logic here
}
}

public static void main(String[] args) {


o de momento, saber que este es el mtodo que invoca la MVJ (Mquina Virtual Java) cuando
tiene que ejecutar esta o cualquier otra aplicacin
o ms adelante ya veremos las palabras reservadas que rodean a este mtodo

Aadir cdigo a la clase Aplicacin


Para que la clase Aplicacin pueda interactuar con un Objeto de tipo Televisor vamos a aadir el siguiente
cdigo al mtodo main(...)
package paqtvestandar;
public class Aplicacion {
public static void main(String[] args) {
Televisor tv;
tv = new Televisor();
tv.canal = 3;
System.out.println("El canal seleccionado es el: " + tv.canal);
}
}

Televisor tv;
o en este punto estamos declarando una variable de referencia tv. De momento su valor es null ya
que todava no apunta a ninguna Instancia u Objeto
tv = new Televisor();
o el operador new nos indica que se acaba de crear un nuevo Objeto, que es una Instancia de la
Clase Televisor
o ahora la variable de referencia tv contiene la direccin de memoria de dicha Instancia
tv.canal = 3;
o como ya tenemos una referencia al Objeto de tipo Televisor, ahora hablamos con su variable de
instancia canal y le decimos que le pasamos el valor 3
System.out.println("El canal seleccionado es el: " + tv.canal);
o mostramos un mensaje indicando el nmero del canal del Objeto de tipo Televisor

Ahora compilamos las Clases Aplicacion y seguidamente la ejecutamos.

Paso 2: Funcionalidad
En este paso vamos a hacer que el usuario pueda subir y bajar el canal del televisor

tipoValorDevuelto
o especifica el tipo de dato devuelto por el mtodo
o ser void, si el mtodo no devuelve ningn valor
o los mtodos que devuelven un valor utilizan la sentencia return

A la Clase Televisor le vamos a aadir los mtodos subirCanal(), bajarCanal() y getCanal()


package paqtvestandar;
public class Televisor {
int canal;
public void subirCanal() {
canal = canal + 1;
}
public void bajarCanal() {
canal = canal - 1;
}
public int getCanal() {
return canal;
}
}

public void subirCanal() {


o como este mtodo no devolver ningn valor , utilizamos la palabra reservada void.
o canal = canal + 1;
 incrementamos en una unidad la variable de instancia o atributo canal.
public int getCanal() {
o delante del mtodo getCanal() indicamos que este mtodo retornar un dato de tipo int.
o return canal;
 utilizamos la palabra clave return para indicar que queremos que este mtodo retorne un
dato.
 en este caso retorna el valor de la variable de instancia canal

Y seguidamente compilamos la Clase Televisor


Invocar mtodos
Para invocar los mtodos de un Objeto, tenemos que tener primeramente una referencia a ese objeto y despus
escribir un punto "." y finalmente el nombre del mtodo que queremos llamar.

Nota: A pesar de que a priori puede parecer ms rpido y cmodo copiar y pegar el cdigo de ejemplo
que estamos siguiendo, te sugiero que lo escribas t mismo en el entorno de NetBeans para que te vayas
familiarizando con ste
o vers que cuando por ejemplo escribes tv. entonces te aparece un men emergente indicndote
cuales son los mtodos que puedes invocar y el tipo de datos que retorna
o si por ejemplo has escrito tv.su y quieres que tambin te aparezca el men emergente, entonces
lo que tienes que hacer es presionar la tecla Control y seguidamente la barra espaciadora
o trabajando de esta forma consigues no cometer fallos de escritura, porque es el mismo entorno
quien va escribiendo el cdigo

Y aqu est el cdigo que tenemos que aadir a la Clase Aplicacion


package paqtvestandar;
public class Aplicacion {
public static void main(String[] args) {
Televisor tv;
tv = new Televisor();
tv.canal = 3;
System.out.println("El canal seleccionado es el: " + tv.canal);
tv.subirCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.bajarCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
}
}

tv.subirCanal();
o como tenemos la variable de referencia tv que apunta a una instancia de tipo Televisor, entonces
nos es posible hablar con el mtodo subirCanal()
System.out.println("El canal seleccionado es el: " + tv.getCanal());
o el mtodo getCanal() nos devuelve un int indicndonos el nmero actual del canal del televisor

Paso 3: Funcionalidad
En este paso vamos a crear dos televisores utilizando diferentes Constructores y vamos a subir y bajar el canal
de los mencionados televisores.
Polimorfismo a travs de la sobrecarga de mtodo
Los Constructores se declaran de la siguiente forma
nombreDelConstructor(listaDeParmetros){
cuerpoDelConstructor
}

tipoValorDevuelto
4

un Constructor no devuelve ningn valor, ni siquiera void


de hecho lo que devuelve es la posicin de memoria dnde residir el objeto que se acaba de
crear
 pero esta posicin de memoria a nivel numrico interno (@FF00AC) est destinada a la
MVJ y no al desarrollador
 de esta forma Java consigue que sus aplicaciones sean ms fiables y seguras ya
que no nos permite posicionarnos en una direccin de memoria directamente, si
no que nos obliga a acceder a estas direcciones a travs de las variables de
referencia devueltas por los Constructores al crear un objeto
nombreDelConstructor
o el nombre del Constructor es el mismo que el nombre de la Clase. Y siguiendo la convencin de
nombres en Java, este nombre tendra que tener
 la primera letra de la primera palabra compuesta en maysculas
 la primera letra de la segunda y restantes palabras compuesta en maysculas
o por tanto una forma rpida de distinguir un Constructor de un mtodo es por la primera letra de
la palabra compuesta
 como ya sabemos en el Constructor esta letra ser mayscula y en el caso de un mtodo
ser minscula
o
o

Nota: para ver tambin la convencin de nombres en los Constructores podemos seguir el vnculo Apndice Convenciones Java y UML - Maysculas y minsculas (II)
A la Clase Televisor le vamos a aadir un Constructor sobrecargado
package paqtvestandar;
public class Televisor {
int canal;
public Televisor(int valorCanal) {
canal = valorCanal;
}
public void subirCanal() {
canal = canal + 1;
}
public void bajarCanal() {
canal = canal - 1;
}
public int getCanal() {
return canal;
}
}
Como podemos observar despus de haber aadido el Constructor sobrecargado en la Clase Televisor, aparece
el siguiente error en la Clase Aplicacion
5

cannot find symbol


symbol: constructor Televisor()
location: class paqtvestandar.Televisor
Create Constructor Televisor() in paqtvestandar.Televisor

Este error nos indica que no encuentra el Constructor sin argumentos de la Clase Televisor. Por tanto, nos
vemos obligados a escribir el Constructor de la Clase Televisor aunque no tenga contenido

si la Clase slo tiene un Constructor sin argumentos y no queremos implementarlo


o no hace falta que ste est escrito dentro de la Clase
si por el contrario, la Clase tiene al menos un Constructor sobrecargado como por ejemplo Televisor(int
valorCanal) y no queremos implementar el Constructor sin argumentos
o el Constructor sin argumentos tiene que estar escrito dentro de la Clase aunque no tenga
contenido
 en cualquiera de los dos casos anteriores, el runtime de Java se crea una especie de
Constructor interno que se denomina Constructor por defecto que utiliza para inicializar
todas las variables de instancia de la Clase con unos valores por defecto
 dependiendo del tipo de datos de las variables de instancia, el Constructor interno
asignar unos valores por defecto u otros:
 tipos de datos primitivos
 son aquellos datos que no son Clases, como por ejemplo boolean,
int, float, double...
 sus valores por defecto son
 boolean: false
 int: 0
 float: 0.0
 double: 0.0
 tipos de datos no primitivos
 son todas las Clases
 el valor por defecto de las Clases es null
 es decir, son variables de referencia que todava no apuntan
a ningn objeto
public Televisor(int valorCanal) {
o a este Contructor le hemos aadido un argumento
o el hecho de que ahora tengamos dos Constructores con una signatura diferente (uno sin
argumento y el otro con un argumento de tipo int) se le llama Sobrecarga de mtodo y es una de
las tres formas de implementar el Polimorfismo
o canal = valorCanal;
 la variable de instancia canal se actualizar cuando se crea una instancia de la Clase
Televisor

Ahora aadimos un Constructor sin argumentos a la Clase Televisor

package paqtvestandar;
public class Televisor {
int canal;
public Televisor() {}
public Televisor(int valorCanal) {
canal = valorCanal;
}
public void subirCanal() {
canal = canal + 1;
}
public void bajarCanal() {
canal = canal - 1;
}
public int getCanal() {
return canal;
}
}

Crear dos objetos del mismo tipo de forma diferente


En ocasiones nos puede convenir inicializar una o ms variables de instancia de un objeto en el mismo
momento que lo estamos creando

si es esto lo que queremos, lo que haremos ser pasar los valores de las variables de instancia que
queremos inicializar como argumento de un Constructor

Ahora vamos a crear dos objetos de tipo Televisor. Uno de ellos estar referenciado por una variable de
referencia llamada tv y el otro por otra variable de referencia llamada televisor
package paqtvestandar;
public class Aplicacion {
public static void main(String[] args) {
Televisor tv;
tv = new Televisor();
System.out.println("El canal por defecto es el: " + tv.canal);
tv.canal = 3;
System.out.println("El canal seleccionado es el: " + tv.canal);
tv.subirCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.bajarCanal();
7

System.out.println("El canal seleccionado es el: " + tv.getCanal());


Televisor televisor = new Televisor(6);
System.out.println("El canal del segundo televisor es el: "
+
televisor.getCanal());
System.out.println("El canal seleccionado es el: " + tv.getCanal());
}
}

System.out.println("El canal por defecto es el: " + tv.canal);


o en este caso el mensaje de salida nos dir que el nmero de canal es el 0, porque ha sido por un
lado declarado por nosotros como variable de instancia y por el Constructor inicializado con su
valor por defecto
Televisor televisor = new Televisor(6);
o hasta el momento, siempre declarbamos primero la variable de referencia y despus crebamos
el objeto por motivos didcticos
 lo habitual es que esto se escriba en una sola lnea
o en este caso el Runtime de Java sabe que tiene que llamar al Constructor que tiene un argumento
de tipo int
System.out.println("El canal del segundo televisor es el: " + televisor.getCanal());
o el segundo televisor que hemos creado nos indica el canal 6
System.out.println("El canal seleccionado es el: " + tv.getCanal());
o y el primer televisor que hemos creado nos indica el canal 3

Paso 4: Funcionalidad
En este paso no vamos a permitir la creacin de un televisor con un valor de canal negativo
Si el valor de un canal es menor que 0, entonces el canal asignado ser el 0.
Sentencia de control de flujo if-else
La sentencia if se utiliza para dirigir la ejecucin de un programa hacia dos caminos diferentes.
Esta es la sintaxis de un control de flujo if-else
if (condicin) {
sentencia1;
sentencia2;
}
else {
sentencia3;
sentencia4;
}

if (condicion) {
o despus de la palabra reservada if, siempre tenemos que abrir un parntesis para incluir dentro
una condicin
o condicin
8

en la siguiente tabla podemos ver los distintos operadores utilizados en las condiciones:
Operador
==
!=
>
<
>=
<=
&&
||

Significado
Igual a
Distinto de
Mayor que
Menor que
Mayor o igual
que
Menor o igual
que
AND
OR

else {
o

si no se cumple la condicin anterior, entonces realizamos otras sentencias

Si slo hubiera una sentencia, es decir una sola lnea de cdigo nos podramos ahorrar los corchetes
if (condicin)
sentencia1;
else
sentencia3;

if (condicin)
o personalmente prefiero utilizar siempre los corchetes aunque slo haya una sentencia porque
 si ms adelante decido aadir una nueva sentencia, los corchetes ya estn all y
 tambin me ayudan a tener una legibilidad de cdigo ms clara

Tambin podemos utilizar sentencias if-else-if mltiples que se basan en una sentencia de if anidados
Esta es la sintaxis de un control de flujo if-else-if
if (condicin) {
sentencia1;
sentencia2;
}
else if (condicin) {
sentencia3;
sentencia4;
}
else {
sentencia5;
}
9

Las sentencias if se ejecutan de arriba a abajo de tal forma que tan pronto como una de las condiciones
de control del if sea verdadera, la sentencia o sentencias asociadas se ejecutan y el resto no se tiene en
cuenta
si ninguna de las condiciones es verdadera, entonces se ejecuta la sentencia else final, que acta como
condicin por defecto
o si no hay sentencia else final y todas las otras condiciones son falsas, entonces no se ejecuta
ninguna sentencia

Vamos a crear una pequea aplicacin con varias sentencias if-else-if mltiples para saber en qu estacin se
encuentra un mes en particular.
package paqsentenciascontrol;
public class EstacionesIfElseIf {
public EstacionesIfElseIf() {
}
public static void main(String[] args) {
int mes = 10;
String strEstacion;
if(mes == 12 || mes == 1 || mes == 2){
strEstacion = "invierno";
}
.
.
.
else {
strEstacion = "desconocido";
}
System.out.println("El mes " + mes + " es " + strEstacion);
}
}

Sentencia de ramificacin mltiple switch


La sentencia switch nos proporciona una forma fcil de ir a partes diferentes del cdigo en funcin del valor de
una expresin.

las expresiones tienen que ser de tipo int, short, char o byte

No cabe duda que es la mejor alternativa a una larga serie de sentencias if-else-if.
Esta es la sintaxis de una ramificacin mltiple switch
10

switch (expresin) {
case valor1:
sentencia1;
sentencia2;
break;
case valor2:
sentencia3;
sentencia4;
break;
case valor3:
sentencia5;
sentencia6;
break;
default:
sentencia7;
}

el mecanismo de la sentencia switch es el siguiente


o el valor de la expresin se compara con cada uno de los valores (valor1, valor2, valor3) de las
sentencias case
 si coincide con alguno
 se ejecuta el cdigo que sigue a la sentencia case
 si no coincide con ninguno
 se ejecuta la sentencia default
 la sentencia default es opcional. Por tanto si ningn case coincide y no hay
una sentencia default entonces no se hace nada
o la sentencia break se utiliza en sentencias switch para finalizar una secuencia de sentencias
 es decir, cuando se encuentra una sentencia break la ejecucin salta a la primera lnea de
cdigo que sigue a la sentencia switch completa. Esto tiene el efecto de salirse del switch

Vamos a crear una pequea aplicacin con una sentencias switch para saber en qu estacin se encuentra un
mes en particular.
Y este es parte del cdigo de la Clase EstacionesSwitch teniendo en cuenta que los meses pertenecen a las
siguientes estaciones

invierno: 12, 1 y 2
primavera: 3, 4 y 5
verano: 6, 7 y 8
otoo: 9, 10, 11
desconocido: cualquier nmero que no est entre el nmero 1 y el 12

11

package paqsentenciascontrol;
public class EstacionesSwitch {
public static void main(String[] args) {
int mes = 14;
String strEstacion;
switch (mes){
case 12:
case 1:
case 2:
strEstacion = "invierno";
break;
.
.
.
}
System.out.println("El mes " + mes + " es " +
strEstacion);
}
}

Ahora vamos a ahondar un poco ms en la sentencia break. Si aadimos el siguiente cdigo


public static void main(String[]
args) {
int mes = 12;
String strEstacion;
switch (mes){
case 12:
System.out.println("case 12");
case 1:
System.out.println("case 1");
case 2:
System.out.println("case 2");
strEstacion = "invierno";
break;
.
.
.
}

12

Como podemos observar en la salida al inicializar la variable mes a valor 12, se han ejecutado las sentencias
correspondientes al case 12, 1 y 2 hasta que se ha encontrado con la sentencia break del case 2 y entonces se ha
salido de la sentencia switch.
Paso 4: Sin canal negativo
En nuestro caso, no vamos a permitir que se construya una instancia de tipo Televisor con un valor de canal
negativo. Para ello vamos a aadir el siguiente cdigo a la Clase Televisor
package paqtvestandar;
public class Televisor {
int canal;
public Televisor() {
}
public Televisor(int valorCanal) {
if (valorCanal < 0){
canal = 0;
}
else {
canal = valorCanal;
}
}
public void subirCanal() {
canal = canal + 1;
}
public void bajarCanal() {
canal = canal - 1;
}
public int getCanal() {
return canal;
}
}

if (valorCanal < 0){


o si el canal es negativo, entonces ejecutamos la sentencia asociada a esta condicin
canal = 0;
o en este caso decimos que la variable de instancia canal toma como valor el nmero 0
o Nota: Ms adelante ya veremos las excepciones, que son un mecanismo muy til para resolver
situaciones de este tipo.

En la Clase Aplicacion vamos a pasarle un valor negativo al Constructor del segundo Televisor
13

package paqtvestandar;
public class Aplicacion {
public Aplicacion() {
}
public static void main(String[] args) {
Televisor tv;
tv = new Televisor();
System.out.println("El canal por defecto es el: " + tv.canal);
tv.canal = 3;
System.out.println("El canal seleccionado es el: " + tv.canal);
tv.subirCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.bajarCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
Televisor televisor = new Televisor(-5);
System.out.println("El canal del segundo televisor es: "+
televisor.getCanal());
System.out.println("El canal seleccionado es el: " + tv.getCanal());
}
}

Televisor televisor = new Televisor(-5);


o como podemos ver, al constructor de Televisor le pasamos un valor de canal negativo
System.out.println("El canal del segundo televisor es el: " + televisor.getCanal());
o y como caba esperar, el mensaje del canal asignado en este momento es el 0

Paso 5: Funcionalidad Encapsulacin


En este paso vamos a impedir que los televidentes puedan acceder directamente a los canales del Televisor.
Si lo intenten tan se encontrarn con errores como ste

canal has private access in paqtvestandar.Televisor

A travs de la Encapsulacin se puede controlar que partes de un programa pueden acceder a los miembros
(variables de instancia y mtodos) de un Objeto

controlando el acceso se pueden prevenir malas actuaciones sobre los datos


la Encapsulacin se basa en el control de acceso o mbito.
o para empezar vamos a conocer los mbitos private y public. Ms adelante conoceremos los
mbitos friendly y protected
o public
 puede ser accedido por cualquier parte del programa
o private
14

slo puede ser accedido por otros miembros de su Clase

El hecho de que hasta ahora accediramos al atributo canal de la instancia de tipo Televisor de esta forma
tv.canal = 3; tiene varios inconvenientes. De momento vamos a ver uno de ellos

no hay validacin del valor asignado


o es decir si un usuario del televisor decide que el canal que quiere ver es el -4, no tenemos ningn
mecanismo para defendernos y "ya nos han colado un gol"

A la Clase Televisor le tenemos que hacer las siguientes modificaciones


package paqtvestandar;
public class Televisor {
private int canal;
public Televisor() {
}
public Televisor(int valorCanal) {
setCanal(valorCanal);
}
public void subirCanal() {
setCanal(canal + 1);
}
public void bajarCanal() {
setCanal(canal - 1);
}
public int getCanal() {
return canal;
}
public void setCanal(int valorCanal) {
if (valorCanal < 0){
canal = 0;
}
else {
canal = valorCanal;
}
}
}

private int canal;


o al indicar que el mbito es private estamos diciendo que slo desde dentro de la Clase Televisor
se puede acceder al atributo canal
15

public Televisor(int valorCanal) {


o no tendramos un cdigo optimizado si tuviramos que filtrar los datos en dos sitios distintos.
 por este motivo, en vez de filtrar el dato correspondiente al canal en el Constructor, lo
haremos solamente en el mtodo setCanal()
o setCanal(valorCanal);
 invocamos a este mtodo por las razones expuestas anteriormente
setCanal(canal + 1);
setCanal(canal - 1);
o cuando el usuario baja el canal, se podra dar el caso que llegara al canal 0 y si sigue bajando el
canal llegara al canal -1.
 para evitar esto invocamos al mtodo setCanal(...) pasndole como argumento el
resultado de la operacin de bajar el canal.
o para seguir una coherencia de cdigo realizamos lo mismo en el caso de que el usuario quisiera
subir el canal
 si ms adelante nos dijeran que por ejemplo el canal ms alto no puede superar el nmero
99, simplemente tendramos que ampliar el filtro en el mtodo setCanal(...)
public void setCanal(int valorCanal) {
o al tener este mtodo un mbito public, este mtodo podr ser llamado
 tanto desde el Constructor de su Clase
 como desde cualquier otra parte del programa que estuviera interesada en conversar con
una instancia de tipo Televisor para cambiarle el canal

Ahora compilamos la Clase Televisor y seguidamente abrimos la Clase Aplicacion. Como podemos observar el
compilador nos da un error indicndonos que la variable de instancia canal tiene acceso privado y que por
consiguiente la Clase Aplicacion no se puede compilar
Para evitar estos errores tenemos que realizar unos pequeos cambios en la Clase Aplicacion
Aqu tenemos el cdigo de la Clase Aplicacion
package paqtvestandar;
public class Aplicacion {
public Aplicacion() {
}
public static void main(String[] args) {
Televisor tv;
tv = new Televisor();
System.out.println("El canal por defecto es el: " + tv.getCanal());
// tv.canal = 3;
tv.setCanal(3);
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.subirCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.bajarCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
Televisor televisor = new Televisor(-5);
16

System.out.println("El canal del segundo televisor es el: "


televisor.getCanal());
System.out.println("El canal seleccionado es el: " + tv.getCanal());

}
}

tv.setCanal(3);
o a diferencia del cdigo de los pasos anteriores tv.canal = 3;
 ahora la Clase Televisor no permite que se acceda directamente a su variable de instancia
canal debido a que esta es privada, pero s permite el acceso a su mtodo setCanal()
porque ste es pblico

Paso 6: Diagrama de Clases UML


UML (Unified Modeling Language, Lenguaje Unificado de Modelado) es un estndar auspiciado por el OMG
(Object Management Group) para realizar las labores de Anlisis y Diseo como antesala al desarrollo de
cualquier aplicacin escrita en un lenguaje Orientado a Objetos.

una de las labores de Diseo es la creacin de los Diagramas de Clases de Diseo


o estos diagramas son muy tiles porque muestran la estructura de las Clases que despus van a
estar escritas en un lenguaje de programacin Orientado a Objetos

Estas son las dos Clases que hemos estado utilizando hasta ahora

Televisor
o una Clase se divide en tres partes. En la primera parte tenemos
 el nombre de la Clase.
 nuestra Clase se llama Televisor
 (from paqtvestandar)
 aqu nos est indicando que la Clase Televisor pertenece al package
(paquete) paqtvestandar
-canal: int
o una Clase se divide en tres partes. En la segunda parte tenemos
 las variables de instancia o atributos
 nuestra Clase de momento tiene un atributo que se llama canal y es del tipo
primitivo int
17

para indicar que su mbito es private, se pone el signo menos delante del nombre
del atributo.

+Televisor():
o una Clase se divide en tres partes. En la tercera parte tenemos
 los mtodos u operaciones de la Clase
 a los Constructores tambin se les considera mtodos
 pero como ya sabemos que un Constructor no devuelve ningn valor,
despus de los dos puntos no aparece la palabra reservada void ni ningn
tipo de dato
 para indicar que su mbito es public se pone el signo ms delante del nombre del
mtodo
+Televisor(valorCanal:int):
o en este caso este Constructor est sobrecargado con el nombre de una variable llamada
valorCanal de tipo int
+subirCanal():void
o en el interior de los parntesis este mtodo no tiene nada, porque no tiene argumentos
o como este mtodo no devuelve ningn valor, utilizamos la palabra reservada void para indicarlo
+getCanal():int
o como este mtodo retorna un valor de tipo entero, lo indicamos con la palabra reservada int
detrs de los dos puntos ":"
Aplicacion
o este es el nombre de la segunda Clase que hemos creado y que pertenece al mismo paquete
+main(args:String[]):void
o de momento saber que est subrayado porque es static

o
o

esta flecha es una Relacin de Dependencia que nos indica que la Clase Aplicacion depende
puntualmente de la Clase Televisor para poder realizar una serie de acciones
<<instantiate>>
 UML utiliza los estereotipos para agregar informacin tanto a las Relaciones como a los
Elementos (un Elemento puede ser por ejemplo una Clase)
 adems de los estereotipos estndar de UML, los usuarios de UML podemos
aadir nuevos estereotipos y as hacer que UML sea extensible
 en nuestro caso concreto estamos diciendo que una de las acciones que puede realizar la
Clase Aplicacion sobre la Clase Televisor es crear instancias (<<instantiate>>) de tipo
Televisor

De esta forma y siguiendo la convencin de los Constructores explcitos e implcitos tenemos el siguiente
Diagrama de Clases de Diseo con un Constructor por defecto y otro Constructor sobrecargado.

18

Paso 7: Ventajas de la Encapsulacin


En este paso vamos a aumentar las prestaciones de nuestro televisor subiendo y bajando la intensidad del color
de la pantalla y modificando el volumen del televisor.
Ahora que ya sabemos conceptualmente que es la Encapsulacin, vamos a estudiar ms a fondo sus ventajas
Validacin de los datos
Ya comentamos la gran ayuda que nos ofrece la Encapsulacin para filtrar datos no deseados
Facilidad de uso de la Clase
Imaginemos que creamos un Objeto de tipo Coche y que un futuro comprador de este coche se acerca a un
concesionario y lo quiere probar antes de comprarlo

gracias a que la operativa bsica de conduccin es relativamente sencilla, el futuro comprador se sentar
en el asiento del conductor y utilizar mtodos pblicos como arrancar(), frenar(), girar(sentido, ngulo)
y acelerar().
o los ingenieros que han creado la Clase Coche han tenido que implementar muchas ms
operativas que las bsicas ya mencionadas
 por ejemplo, cuando el futuro comprador ha invocado el mtodo acelerar(), ste mtodo a
su vez ha llamado a otros mtodos como inyectarGasolina(), moverPistones(),
transmitirFuerzaAlPalier() y moverRuedas()
o Si este futuro comparador fuera un desarrollador de software que tiene que interactuar con una
instancia de la Clase Coche, ste podra seguir un Diagrama de Clases como este:

19

En vez de seguir este otro en el que se muestra un atributo llamado suministradorCombustible1


que es de tipo Carburador y los mtodos inyectarGasolina(), moverPistones(),
transmitirFuerzaAlPalier() y moverRuedas() relacionados con el hecho de querer aumentar la
velocidad del coche invocando al mtodo acelerar().

en la vida real sucede lo mismo, todas las cosas que nos rodean son Objetos con sus atributos y
operativas para que podamos interactuar con ellos.
 si no pudiramos tener diferentes niveles de abstraccin con las cosas que nos rodean,
tendramos que ser expertos en casi todo con el fin de poder utilizarlo
en este ejemplo slo hemos imaginado los mtodos que un ingeniero tendra que implementar
para poder acelerar, pero sigamos imaginando y pensemos en la cantidad de mtodos que todava
se tendran que aadir para por ejemplo realizar giros, frenar o arrancar el coche
gracias a la Encapsulacin, pueden haber desarrolladores especializados en crear Clases de bajo
nivel con una gran complejidad intrnseca, pero que su utilizacin es extremadamente sencilla
 de esta forma utilizamos atributos y mtodos de mbito private para realizar tareas de
bajo nivel (todo lo que se encuentra debajo del cap) que slo pueden ser invocadas
desde el interior del propio Objeto y mtodos de mbito public para que puedan ser
invocados tanto desde el interir del propio Objeto como desde otro Objeto

Documentacin menos extensa y por lo tanto ms gil


La documentacin entregada al desarrollador o desarrolladores que quieren interactuar con los Objetos de tipo
Coche ser evidentemente mucho menos extensa que la que utilizan los desarrolladores que han creado esta
Clase

todos los atributos y mtodos de mbito private no se muestran ni se explican en dicha documentacin

Flexibilidad en el cambio de versiones


Finalmente ya hemos cumplido con nuestro objetivo de crear la Clase Coche y ya hay muchos usuarios que
desde sus aplicaciones interactan con las instancias de nuestro coche

pero la gran mayora de los usuarios opinan que nuestro coche les est arruinando sus bolsillos cada vez
que tienen que repostar
debido a esto, nos vemos obligados a realizar una serie de cambios importantes en nuestra Clase para
que los usuarios no se tengan que gastar tanto dinero en combustible

20

por tanto creamos la versin 2.0, la cual ya no funciona con un Carburador sino que funciona con una
BombaInyectora propia de los coches Diesel, e intercambiamos el mtodo inyectarGasolina() por el
mtodo inyectarGasoil().

Entregamos la nueva versin a nuestros usuarios, y les indicamos que la operativa del coche sigue siendo
exactamente la misma que en la versin 1.0.

esto es posible debido a que ellos nunca llegaron a interactuar con el atributo
suministradorCombustible1 ni con el mtodo inyectarGasolina(), y por lo tanto
o nosotros como desarrolladores de la Clase Coche
 hemos tenido total libertad y flexibilidad para realizar los cambios necesarios
o y los usuarios
 no han tenido que modificar ni una sola lnea de cdigo de los Objetos que interactan
con nuestra Clase

Paso 7: Operativa
Subir y bajar la intensidad del color del televisor
Ahora queremos que el Televisor estndar adems de ofrecer la operativa de cambiar los canales, tambin nos
permita aumentar y disminuir la intensidad del color. Para ello vamos a crear cuatro nuevos mtodos:

21

Este es la implementacin de la Clase Televisor


package paqtvestandar;
public class Televisor {
private int canal;
public Televisor() {
}
public Televisor(int valorCanal) {
setCanal(valorCanal);
}
public void subirCanal() {
setCanal(canal + 1);
}
public void bajarCanal() {
setCanal(canal - 1);
}
public int getCanal() {
return canal;
}
public void setCanal(int valorCanal) {
if (valorCanal < 0){
canal = 0;
}
else {
canal = valorCanal;
}
}
public void subirColor(){
System.out.println("Televisor - subirColor(): estoy subiendo el
color");
subirColorAyuda();
}
private void subirColorAyuda() {
System.out.println("Televisor - subirColorAyuda(): sigo subiendo el
color");
}
public void bajarColor(){
System.out.println("Televisor - bajarColor(): estoy bajando el
22

color");
bajarColorAyuda();
}
private void bajarColorAyuda() {
System.out.println("Televisor - bajarColorAyuda(): sigo bajando el
color");
}
}

public void subirColor(){


o System.out.println("Televisor - subirColor(): estoy subiendo el color");
 este mtodo empieza a subir la intensidad del color del televisor
o subirColorAyuda();
 pero llega un momento que tiene la necesidad de invocar a otro mtodo que har trabajos
de ms bajo nivel y que slo ser invocado desde dentro del Objeto de tipo Televisor
porque este mtodo es de mbito private
private void subirColorAyuda() {
o System.out.println("Televisor - subirColorAyuda(): sigo subiendo el color");
 mostraremos este tipo de mensaje y otros parecidos a medida que el flujo del programa
vaya pasando por ellos

Compilamos la Clase Televisor y seguidamente modificamos la clase Aplicacion


package paqtvestandar;
public class Aplicacion {
public static void main(String[] args) {
Televisor tv;
tv = new Televisor();
System.out.println("El canal por defecto es el: " + tv.getCanal());
tv.setCanal(3);
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.subirCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.bajarCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
Televisor televisor = new Televisor(-5);
System.out.println("El canal del segundo televisor es el: "
+ televisor.getCanal());
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.subirColor();
// tv.subirColorAyuda();
}
}

23

Al ejecutar la Clase Aplicacion vemos los mensajes correspondientes a los mtodos subirColor() y
subirColorAyuda()
Si descomentamos la invocacin al mtodo subirColorAyuda() apuntado por la variable de referencia tv, vamos
a poder ver que el compilador se queja (y con razn!) porque estamos intentando acceder a un mtodo de
mbito private
Subir y bajar el volumen del televisor
Segn el siguiente Diagrama de Clases de Diseo

Vamos a implementa las Clases Televisor y Aplicacion de tal forma que cuando creemos una instancia de
Televisor, sta ya tenga el volumen por defecto en posicin 5 sin que se lo tengamos que indicar desde la Clase
Aplicacion de forma explcita
Por lo que respecta a la implementacin de los mtodos subirVolumen() y bajarVolumen(), no tendremos en
cuenta los valores negativos ni tampoco el valor mximo del volumen, as que tendremos que implementar estos
mtodos con el siguiente cdigo
volumen = volumen + 1
volumen = volumen - 1

Desde la Clase Aplicacion tenemos que

crear una instancia de Televisor


seguir cambiando los canales y subiendo el color como en el ejemplo anterior
subir el volumen una posicin
mostrar un mensaje diciendo que "La posicin del volumen es: "....
Aqu tenemos el cdigo del televisor estndar

24

package paqtvestandar;
public class Televisor {
private int canal;
private int volumen = 5;
public Televisor() {}
public Televisor(int valorCanal) {
setCanal(valorCanal);
}
public void subirCanal() {
setCanal(canal + 1);
}
public void bajarCanal() {
setCanal(canal - 1);
}
public int getCanal() {
return canal;
}
public void setCanal(int valorCanal) {
if (valorCanal < 0){
canal = 0;
}
else {
canal = valorCanal;
}
}
public void subirColor(){
System.out.println("Televisor - subirColor(): estoy subiendo el color");
subirColorAyuda();
}
private void subirColorAyuda() {
System.out.println("Televisor - subirColorAyuda(): sigo subiendo el color");
}
public void bajarColor(){
System.out.println("Televisor - subirColor(): estoy bajando el color");
bajarColorAyuda();
}
private void bajarColorAyuda() {
System.out.println("Televisor - bajarColorAyuda(): sigo bajando el color");
}
public void subirVolumen() {
volumen = volumen + 1;
}
public void bajarVolumen() {
volumen = volumen - 1;
25

}
public int getVolumen() {
return volumen;
}
}

Y este es el cdigo modificado de la Clase Aplicacion


package paqtvestandar;
public class Aplicacion {
public static void main(String[] args) {
Televisor tv;
tv = new Televisor();
System.out.println("El canal por defecto es el: " + tv.getCanal());
tv.setCanal(3);
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.subirCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.bajarCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
Televisor televisor = new Televisor(-5);
System.out.println("El canal del segundo televisor es el: "
+
televisor.getCanal());
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.subirColor();
tv.subirVolumen();
System.out.println("La posicin del volumen es: " + tv.getVolumen());
}
}

Paso 8: Herencia a travs de las relaciones de Generalizacin


En este paso vamos a crear un nuevo televisor con las mismas prestaciones que el televisor original.
El nuevo televisor nos permite desconectar el sonido sin tener que modificar el volumen.
Despus de mucho trabajo y esfuerzo hemos conseguido crear un televisor estndar con una funcionalidad
suficiente para poder ser utilizado.
A partir de este televisor estndar, vamos a crear un nuevo televisor que tendr una funcionalidad aadida

para ponerlo en prctica, nos vamos a crear un televisor que lo llamaremos TelevisorVirtual y que nos
va a permitir desconectar el sonido en caso de que por ejemplo recibiramos una llamada telefnica y no
quisiramos bajar el volumen paulatinamente,
o es decir invocando al mtodo bajarVolumen() n veces seguidas
26

Este es su Diagrama de Clases de Diseo correspondiente

este tipo de flecha en UML representa una relacin de Generalizacin


 este tipo de relacin
 nos indica que la Clase hija, en este caso TelevisorVirtual, hereda todos los
atributos y mtodos de la Clase padre, en este caso Televisor
 es muy conveniente cuando queremos crear una Clase muy afn a otra u otras
Clases , pero que no se ajusta cien por cien a nuestras necesidades
 entonces lo que hacemos es implementar los nuevos mtodos de nuestra
Clase y nos ahorramos el tener que escribir o copiar-y-pegar cdigo que ya
ha sido escrito anteriormente. Este cdigo que reutilizamos puede ya haber
sido escrito
 por nosotros mismos,
 por otra persona de nuestro departamento o de nuestra empresa
 o por cualquier otra persona u organizacin que no pertenezca a
nuestra empresa
 gracias a la herencia, se puede crear una Clase general que define caractersticas comunes
a un conjunto de elementos relacionados. Esta Clase puede ser heredada por otras Clases
27

ms especficas, aadiendo a cada una de estas Clases especficas aquellas cosas que son
particulares a ellas
 la Clase general recibe el nombre de Superclase o Clase padre
 a las Clases ms especficas se les llama Subclases o Clases hijas
 una Subclase puede ser a su vez una Superclase de una Subclase y as
sucesivamente
Ahora vamos a crear una nueva Clase llamada TelevisorVirtual que va a heredar de la Clase Televisor
Este es el cdigo de la Clase TelevisorVirtual
package paqtvestandar;
public class TelevisorVirtual extends Televisor {
private boolean sonido = true;
public void setSonido(boolean valorSonido){
sonido = valorSonido;
}
public boolean isSonido(){
return sonido;
}
}

public class TelevisorVirtual extends Televisor {


o en Java, cuando una Clase hereda de otra se indica con la palabra reservada extends
private boolean sonido = true;
o declaramos una variable booleana y hacemos que tome el valor verdadero cuando se cree una
instancia de la Clase
public void setSonido(boolean valorSonido){
o si algn televidente decide ver las imgenes pero no escuchar el televisor, entonces lo que tiene
que hacer es
 invocar este mtodo con la variable valorSonido con valor falso
public boolean isSonido(){
o de la misma forma que existe la convencin de utilizar los getters y setters para acceder a las
variables de instancia, tambin es muy habitual utilizar el prefijo is para saber el estado de una
variable de instancia booleana

Compilamos la Clase TelevisorVirtual.


Para que la Clase Aplicacion pueda interactuar con la Clase TelevisorVirtual, vamos a tener que realizar
bastantes cambios en la Clase Aplicacion.

para que podamos mantener el cdigo de lo que hemos estado haciendo hasta ahora, vamos a realizar
una copia de las Clases Aplicacion y Televisor
o el IDE NetBeans a la copia de estas Clases las llamar Aplicacion_1 y Televisor_1.
28

nosotros seguiremos trabajando sobre las Clases Aplicacion y Televisor y dejaremos las
Clases copiadas como clases histricas para poderlas repasar en el futuro siempre que
queramos

Ahora vamos a hacer que la Clase Aplicacion_1 interacte con la Clase Televisor_1.
package paqtvestandar;
public class Aplicacion_1 {
public static void main(String[] args) {
Televisor_1 tv;
tv = new Televisor_1();
System.out.println("El canal por defecto es el: " + tv.getCanal());
tv.setCanal(3);
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.subirCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.bajarCanal();
System.out.println("El canal seleccionado es el: " + tv.getCanal());
Televisor_1 televisor = new Televisor_1(-5);
System.out.println("El canal del segundo televisor es el: "
+
televisor.getCanal());
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.subirColor();
// tv.subirColorAyuda();
}
}
Modificacin por completo de la Clase Aplicacion
Este es el nuevo cdigo que sustituye al cdigo anterior de Clase Aplicacion
package paqtvestandar;
public class Aplicacion {
public static void main(String[] args) {
TelevisorVirtual tv = new TelevisorVirtual();
tv.setCanal(3);
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.subirColor();
tv.setSonido(false); // Desactivamos el sonido
System.out.println("El televisor tiene el sonido: " + tv.isSonido());
}
}

TelevisorVirtual tv = new TelevisorVirtual();


o con el operador new creamos una instancia de la Clase TelevisorVirtual
29

tv.setCanal(3);
o si nos fijamos, la Clase TelevisorVirtual no contiene el mtodo setCanal(int valorCanal), pero s
que lo tiene su Clase padre Televisor
 como TelevisorVirtual hereda de Televisor, la variable de referencia tv puede invocar
tanto a mtodos propios de la Clase TelevisorVirtual como a mtodos propios de la Clase
Televisor
tv.setSonido(false);
o desactivamos el sonido
System.out.println("El telvisor tiene el sonido: " + tv.isSonido());
o verificamos que el sonido est desactivado

Paso 9: Polimorfismo a travs de la sobre escritura de mtodo


En este paso el nuevo televisor conecta el sonido automticamente al subir o bajar el volumen.
Al ejecutar la Clase Aplicacion vemos como el sonido se ha activado por el hecho de haber subido el volumen
Cuando al nuevo televisor virtual le desconectamos el sonido, ste se queda en silencio.
Para volver a conectar el sonido simplemente tenemos que invocar al mtodo setSonido(true)

pero ganaramos en flexibilidad si diramos al televidente la posibilidad de conectar el sonido de forma


automtica si ste decidiera invocar los mtodos subirVolumen() o bajarVolumen()
o pero estos mtodos ya estn implementados en la Clase Televisor. Entonces Qu podemos
hacer? Este es el Diagrama de Clases de Diseo actualizado para esta nueva situacin:

30

+subirVolumen():void
o la segunda forma de implementar el Polimorfismo es a travs de la sobreescritura de mtodo. (La
primera forma de implementarlo fue a travs de la sobrecarga de mtodo)
 la sobre escritura de mtodo consiste en volver a implementar en la Subclase uno o ms
mtodos que ya estn implementados en la Superclase
 esta tcnica nos es extremadamente til cuando queremos heredar de una
Superclase pero la operativa de uno o ms mtodos heredados de dicha Superclase
no se ajusta a la operativa que nosotros queremos aplicar a la nueva Subclase

Este es el cdigo ampliado de la Clase Televisor Virtual


package paqtvestandar;
public class TelevisorVirtual extends
Televisor {
private boolean sonido = true;
public TelevisorVirtual() {
}
public void setSonido(boolean
valorSonido){
sonido = valorSonido;
}
public boolean isSonido(){
return sonido;
}
public void subirVolumen() {
super.subirVolumen();
if (this.isSonido() == false){
setSonido(true);
}
}
public void bajarVolumen() {
super.bajarVolumen();
if (!isSonido()){
setSonido(true);
}
}
}

public void subirVolumen() {


o en este caso la sobreescritura de mtodo es posible porque la signatura de mtodo del mtodo
subirVolumen() de la Subclase coincide con la signatura de mtodo del mtodo
subirVolumen()de la Superclase
31

para que dos mtodos tengan la misma signatura, stos tienen que tener
 el mismo nombre de mtodo
 el mismo nmero de argumentos
 y que estos argumentos coincidan con el mismo tipo de datos
dentro de este mtodo tenemos que escribir nuestro nuevo cdigo
super.subirVolumen();
 la palabra clave super, se utiliza para indicar que queremos invocar un mtodo que se
encuentra en la Superclase y as poder distinguirlo del mismo mtodo que se encuentra en
la Subclase.
 en nuestro caso, la funcionalidad de bajarVolumen() de la Superclase Televisor se
ajusta a nuestras necesidades y por tanto no la volvemos a escribir. De esta forma
 nos ahorramos tener que volver a escribir o cortar-y-pegar el mismo
cdigo
 y sobre todo evitamos tener el mismo cdigo diseminado por toda la
aplicacin, y con el consiguiente engorro y el riesgo de error de tener que
actualizarlo en "800" sitios si se tuviera que modificar dicho cdigo
if (this.isSonido() == false){
 la palabra clave this, se utiliza para indicar que queremos invocar a un mtodo que se
encuentra en la propia Clase.
 en nuestro caso, invocamos al mtodo this.isSonido() para saber si el sonido est
conectado o desconectado
if (!isSonido()){
 la ausencia de la palabra clave this, tambin se utiliza para indicar que queremos invocar
a un mtodo que se encuentra en la propia Clase.
 si el cdigo lo genera un Asistente o Wizard del entorno de desarrollo, ste lo que
acostumbra hacer al escribir cdigo por nosotros es poner de forma explcita la
palabra clave this.
 si el cdigo lo escribimos nosotros, lo habitual es no utilizar la palabra clave this,
porque sin ella ya se sobreentiende que estamos invocando a mtodos de nuestra
propia Clase
 (!isSonido())es equivalente a (isSonido() == false)
setSonido(true);
 activamos el sonido


o
o

Despus de haber aadido el nuevo cdigo compilamos la Clase TelevisorVirtual.


Y este es el cdigo de la Clase Aplicacion que interacta con una instancia de tipo TelevisorVirtual
package paqtvestandar;
public class Aplicacion {
public Aplicacion() {
}
public static void main(String[] args) {
TelevisorVirtual tv = new TelevisorVirtual();
tv.setCanal(3);
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.subirColor();
32

tv.setSonido(false); // Desactivamos el sonido


System.out.println("El telvisor tiene el sonido: " + tv.isSonido());
tv.subirVolumen();
System.out.println("La posicin del volumen es: " + tv.getVolumen());
System.out.println("El televisor tiene el sonido: " + tv.isSonido());
}
}

tv.subirVolumen();
o desde la Clase Aplicacion nos es totalmente transparente el hecho de que ahora el mtodo
subirVolumen() est sobrescrito en la Clase TelevisorVirtual, desde aqu no percibimos ninguna
diferencia
System.out.println("El televisor tiene el sonido: " + tv.isSonido());
o comprobamos que el sonido se ha activado sin que se lo hayamos indicado de forma explcita
con el mtodo setSonido(true)

Al ejecutar la Clase Aplicacion vemos como el sonido se ha activado por el hecho de haber subido el volumen

33