Está en la página 1de 15

Taller 10-11-12

ST0242 039
DIS

28 de abril de 2020
Entrega: Mayo 15 hasta las 18:00

1. Preliminares
El objetivo de este taller es repasar los conceptos de herencia, relaciones entre
clases y clases abstractas.
Este taller es calificable y hace parte del 10 % de seguimiento que tiene la
materia. La entrega del taller por el respositorio de subversion. Los problemas
que involucran programación se implementan en projectos de BlueJ y se suben
al repositorio. Los ejercicios son para el aprendizaje de cada estudiante. No es
necesario entregar la solución.
Para los problemas cuya solución es texto, respondalos en el README.TXT
del proyecto creado en BlueJ (El README se muestra en BlueJ como una hoja
de escritura).

Introducción
La Programación Orientada a Objetos ha permitido un avance muy importante
en la industria de software. Una de las principales causas es que facilita la Reuti-
lización del Software. Esto se refiere a lo siguiente: Una vez un miembro de un
equipo de desarrollo ha escrito un código que funciona bien, es posible que otro
miembro del equipo lo utilice en otra parte de la aplicación; evitando ası́ “reinven-
tar la rueda”.

1
La mayor parte de los expertos coinciden en que los componentes principales
de la programación orientada a objetos (POO u OOP por sus siglas en inglés - Ob-
ject Oriented Programming) [3] son: encapsulamiento, herencia y polimorfismo.
En el curso ya hemos visto el concepto de encapsulamiento. Se refiere a que
los atributos de una clase, cuando se declaran privados, quedan encapsulados al
interior de la misma. Esto es, las otras clases solamente tienen acceso a esos atri-
butos a través de métodos que el programador de la clase ha construido. Esto
presenta dos venajas: (i) Unos métodos bien escritos garantizan la integridad y se-
guridad de los datos y (ii) el programador puede, en un futuro, hacer cambios en
la forma como se almacenan los atributos al interior del objeto. Siempre y cuando
la forma de invocar los métodos no cambie, el programador de la clase puede, por
ejemplo, usar alguna estructura de datos más eficiente, y no es necesario hacer
cambios en otras clases.
Esta semana hemos introducido los temas de herencia y polimorfismo. En
este taller profundizaremos en la manera en que se implementan estos conceptos
en Java.

2. Herencia
Wikipedia [1] define la herencia, en el contexto de Programación Orientada a
Objetos, de la siguiente manera:

“In object-oriented programming, inheritance is the mechanism


of basing an object or class upon another object (prototype-based
inheritance) or class (class-based inheritance), retaining similar im-
plementation. Also defined as deriving new classes (sub classes) from
existing ones such as super class or base class and then forming them
into a hierarchy of classes. ”

Cuando usamos la herencia entre clases, por ejemplo al decir que la clase B
hereda de la clase A, estamos diciendo que la clase B (o clase derivada) hereda
tanto los atributos como los métodos de la clase A (o clase base). Esto es: no es
necesario incluir en B la declaración de los atributos ni los métodos.
Ahora bien, lo que ocurre, es que el programador de la clase B puede hacer lo
siguiente: (i) Utilizar los atributos y métodos de la clase A sin cambio alguno (ii)
Sobreescribir (o redefinir) algunos atributos o métodos de tal forma que funcionen
de manera diferente. (iii) Agregar nuevos atributos y métodos. En este taller vamos
a ver varios ejemplos de las situaciones anteriores.

2
Figura 1: Version 1 del juego

En los siguientes párrafos, vamos a crear las clases para un juego RPG [5]
Como punto de partida, vamos a definir que nuestro juego RPG tendrá: Humanos,
Monstruos y Armas.
Para comenzar, tendremos las clases descritas en la figura 1.
Inicialmente la clase Humano solamente tiene el atributo para el nombre y el
número de vidas con que cuenta el personaje. Cuando el número de vidas llega a
0, el jugador pierde el juego.

1 p u b l i c c l a s s Humano
{
3 S t r i n g nombre ;
int vidas ;
5 }

La clase Monstruo inicialmente tiene atributos para el nombre del monstruo y


la cantidad de sangre en litros. Cuando la cantidad de sangre llega a 0, el monstruo
muere.

3
1 p u b l i c c l a s s Monstruo
{
3 S t r i n g nombre ;
i n t sangre ;
5 }

La clase Arma contiene la información del nombre del arma, ası́ como la can-
tidad de daño que le infringe al enemigo. Un punto de daño equivale a un litro de
sangre de un monstruo y equivale a 1/10 de la vida de un humano.

1 p u b l i c c l a s s Arma
{
3 S t r i n g nombre ;
i n t danyo ;
5 }

Problema 1. (10 %) Ingrese en BlueJ, cree un proyecto que se llame JuegoRPG,


cree las clases Humano, Monstruo y Arma.

Ejercicio 1. Utilizando el código del ejercicio anterior, cree unas instancias de


cada clase. A pesar de que no hemos agregado métodos constructores, es posible
crear instancias, porque Java ha creao un constructor, sin parámetros, en cada
clase.
Ahora vamos a crear un tipo de Monstruo: un Orco. Un Orco es un Monstruo,
y por lo tanto para crear la clase Orco, vamos a heredar de la clase Monstruo.
Una posibilidad para verificar si tiene sentido que una clase B herede de una
clase A es preguntarnos si una instancia de B también es una instancia de A. En el
ejemplo, nos preguntamos si el Orco es un Monstruo. A esto se le llama en inglés
una relación is-a.
El cóigo de la clase Orco será de la siguiente manera:

1 p u b l i c c l a s s Orco e x t e n d s M o n s t r u o
{
3
}

4
Figura 2: Representación de la relación de herencia en BlueJ

Notar el uso de la palabra clave extends, que indica que la clase Orco hereda
de la clase Monstruo.
Una vez hemos creado la clase Orco, BlueJ nos muestra la relación de herencia
con la clase Monstruo con una flecha continua que tiene un triángulo en la punta.

Ejercicio 2. Consultar en Internet, por ejemplo en la página [6], Cómo se le


llama a este tipo de relaciones en el lenguaje UML y cómo se representa gráfica-
mente.

Problema 2. (10 %) Crear la clase Orco.


Luego crear una instancia de la clase Orco. Al inspeccionar la instancia del
Orco, ¿qué atributos aparecen? ¿Por qué hay atributos en el Orco si no los hemos
programado?
Ahora bien, queremos que el Orco tenga un nombre, un valor inicial de Sangre
y, adicionalmente, una forma de gruñir.
Los atribuots nombre y sangre están definidos en la clase base, esto es, en
Monstruo. Para darle valores iniciales a estos atributos, debemos hacer lo siguien-
te:

Problema 3. (20 %) Crear lo siguiente:

Crear un constructor en la clase Monstruo para inicializar los valores nombre


y sangre

5
Agregar en Orco un atributo tipo S tring que permita almacenar el valor del
gruñido.

Crear un constructor en la clase Orco que reciba los valores de nombre,


sangre y tipo de rugido para cada nueva instancia de Orco

En el constructor del Orco, invocar el constructor de la clase base, pasándole


los atributos correspondientes.

Luego de estos cambios, las clases Monstruo y Orco quedan de la siguiente


manera:

p u b l i c c l a s s Monstruo
2 {
S t r i n g nombre ;
4 i n t sangre ;

6 p u b l i c M o n s t r u o ( S t r i n g nombre , i n t s a n g r e ) {
t h i s . nombre = nombre ;
8 t h i s . sangre = sangre ;
}
10 }

p u b l i c c l a s s Orco e x t e n d s M o n s t r u o
2 {
String grunyido ;
4
p u b l i c Orco ( S t r i n g nombre , i n t s a n g r e , S t r i n g g r u n y i d o ) {
6 s u p e r ( nombre , s a n g r e ) ;
t h i s . grunyido = grunyido ;
8 }

10 }

Es importante notar el uso de la palabra clave super, que hace referencia a


que desde la clase derivada se está invocando el constructor de la clase base.
Notar también que el constructor de la clase Orco recibe valores para todos sus
atributos. En el caso de los atributos heredados (nombre y sangre), se le “pasan” a

6
la clase base mediante la invocacaión de su constructor, y en el caso de su propio
atributo (grunyido), se asigna de la manera que hemos visto anteriormente en el
curso.

Ejercicio 3. Crear una instancia de Orco. Ahora es necesario proveer valores


para el nombre, la sangre y el grunyido. Inspeccionar la instancia y verificar que
todos los valores quedan almacenados dentro de la instancia del Orco, a pesar de
que algunos de ellos sean heredados de la clase Monstruo.

Ejercicio 4. Crear una clase Dragon. Esta clase también hereda de Monstruo
y, por lo tanto, comparte los atributos nombre y sangre. Los dragones tienen un
atributo adicional, y es el tipo de escamas. Algunos tienen escamas de metal y
otros de cuero. El tipo de escamas se guarda en una variable que se llama escamas
y es de tipo S tring.

Ejercicio 5. ¿Qué error produce Java cuando no se crea un constructor en la


clase Dragon? ¿A qué se debe este error? ¿Cómo se corrige?

2.1. Modificadores de acceso


Ahora vamos a ver qué ocurre con los modificadores de acceso private y
protected.

Problema 4. (20 %) Vamos a agregar el método imprimirNombre() a la clase


Orco:

p u b l i c c l a s s Orco e x t e n d s M o n s t r u o
2 {
String grunyido ;
4
p u b l i c Orco ( S t r i n g nombre , i n t s a n g r e , S t r i n g g r u n y i d o ) {
6 s u p e r ( nombre , s a n g r e ) ;
t h i s . grunyido = grunyido ;
8 }

10 p u b l i c void imprimirNombre ( ) {
System . o u t . p r i n t l n ( ”Mi nombre e s : ” + nombre ) ;
12 }

7
14 }

La idea es que podamos saber cómo se llama un orco.

Ejercicio 6. Poner modificador de acceso private a los atributos de la clase


Monstruo. Al compilar el proyecto, ¿qué error produce Java? ¿Por qué?

Ejercicio 7. Ahora poner modificador de acceso protected a los atributos de


la clase Monstruo. Explicar la diferencia con el ejercicio anterior.

3. Polimorfismo
Algo es polimórfico cuando tiene varias formas. En Programación Orientada
a Objetos tiene el siguiente significado, tomado de Webopedia: [4]

”Generally, the ability to appear in many forms. In object-oriented


programming, polymorphism refers to a programming language’s abi-
lity to process objects differently depending on their data type or
class. More specifically, it is the ability to redefine methods for de-
rived classes. For example, given a base class shape, polymorphism
enables the programmer to define different area methods for any num-
ber of derived classes, such as circles, rectangles and triangles. No
matter what shape an object is, applying the area method to it will
return the correct results. Polymorphism is considered to be a requi-
rement of any true object-oriented programming language (OOPL).”

Para ver este concepto en funcionamiento, vamos a hacer lo siguiente:

3.1. Referencias
Problema 5. (20 %) Crear lo siguiente:

Vamos a crear una clase Juego, donde se van a manejar las referencias a
todas las instancias de Humano y Monstruo del juego. Inicialmente vamos
a tener una referencia a un Monstruo

8
Vamos a agregar un método moverse() en la clase Monstruo. Como se defi-
ne en la clase base, se hereda automáticamente en las clases Orco y Dragon.

Vamos a hacer implementaciones especı́ficas en la clase Orco, para decir


que cuando un orco se mueve, corre.

El código queda de la siguiente manera:


La clase Juego:

p u b l i c c l a s s Juego
2 {
M o n s t r u o m1 ;
4
p u b l i c v o i d a s i g n a r M o n s t r u o ( M o n s t r u o m1 ) {
6 t h i s . m1 = m1 ;
}
8

La clase Monstruo:

1 p u b l i c c l a s s Monstruo
{
3 p r o t e c t e d S t r i n g nombre ;
protected i n t sangre ;
5
p u b l i c M o n s t r u o ( S t r i n g nombre , i n t s a n g r e ) {
7 t h i s . nombre = nombre ;
t h i s . sangre = sangre ;
9 }

11 p u b l i c void moverse ( ) {

13 }
}

La clase Orco:

9
Figura 3: Representación de la relación entre clases en BlueJ

p u b l i c c l a s s Orco e x t e n d s M o n s t r u o
2 {
String grunyido ;
4
p u b l i c Orco ( S t r i n g nombre , i n t s a n g r e , S t r i n g g r u n y i d o ) {
6 s u p e r ( nombre , s a n g r e ) ;
t h i s . grunyido = grunyido ;
8 }

10 p u b l i c void imprimirNombre ( ) {
System . o u t . p r i n t l n ( ”Mi nombre e s : ” + nombre ) ;
12 }

14 p u b l i c void moverse ( ) {
System . o u t . p r i n t l n ( ” Soy un o r c o , e s t o y c o r r i e n d o ” ) ;
16 }
}

Ejercicio 8. Copiar el código anterior en las clases del proyecto.


Lo primero que podemos notar, es que BlueJ muestra una flecha punteada
desde la clase Juego hacia la clase Monstruo. Esto significa que en Juego tenemos
una referencia a un objeto que es de tipo Monstruo.

Ejercicio 9. Consultar cómo se llama la relación en UML cuando desde una


clase C se tiene una referencia a un objeto del tipo D y cómo se representa gráfi-
camente.

Problema 6. (20 %) Crear una instancia de Juego. Ahora crear una instancia
de Orco y asignarla al juego usando el método asignarMonstruo(). ¿Funciona,

10
si o no? Por qué puedo asignar un objeto tipo Orco a una variable que espera algo
de tipo Monstruo? Explicar.

Ejercicio 10. Ahora crear una instancia de Dragon y asignarla al juego. ¿Fun-
ciona, si o no? Explicar.Ahora vamos a modificar la clase Juego para que alma-
cene un arreglo de 4 monstruos. Los monstruos serán creados y asignados en el
constructor del juego.

Ejercicio 11. En este punto, debe agregar un método moverse a la clase Dragon,
en el cual se diga que el dragón vuela.
Tambien vamos a crear un método moverMonstruos, que va a invocar el méto-
do moverse de cada uno de los monstruos almacenados en el arreglo.
El código queda ası́:

1 p u b l i c c l a s s Juego
{
3 Monstruo [ ] a r r ;

5 public Juego ( ) {
arr = new M o n s t r u o [ 4 ] ;
7 arr [ 0 ] = new Orco ( ” Garnag ” , 1 0 , ” g a r r ” ) ;
arr [ 1 ] = new Dragon ( ” B r e n t o n ” , 2 0 , ” m e t a l ” ) ;
9 arr [ 2 ] = new Orco ( ” Rogthun ” , 5 , ” p u r r ” ) ;
arr [ 3 ] = new Dragon ( ” Draco ” , 4 0 , ” c u e r o ” ) ;
11 }

13 p u b l i c void moverMonstruos ( ) {
f o r ( i n t i = 0 ; i < a r r . l e n g t h ; i ++) {
15 a r r [ i ] . moverse ( ) ;
}
17 }
}

Ejercicio 12. Entrar el código de la clase Juego, como se explica en el código


anterior.

Ejercicio 13. Al crear una instancia de la clase Juego e invocar el método


moverMonstruos(), ¿cuál es el resultado? Este es un ejemplo de polimorfismo,

11
ya que, en teorı́a, se está invocando el método moverse a cada entrada del arreglo
de Monstruos, esto es, se está invocando el moverse a los Monstruos. Sin embar-
go, evidentemente se invoca el método especı́fico de los dragones y el método
especı́fico de los orcos. Explicar con sus palabras.

Ejercicio 14. En la clase Juego, se están agregando orcos y dragones al arreglo


arr, pero el arreglo arr es un arreglo para almacenar referencias a Monstruo.
¿Funciona, si o no? ¿Por qué? Explicar con sus palabras.

3.2. Estructura de datos ArrayList


Ahora vamos a introducir un tipo de estructura de datos que se llama ArrayList.
Ver la documentación en: [2]
Esta estructura tiene las ventajas de un arreglo (Array), ya que se puede acce-
der a un elemento en una posición determinada de manera directa, pero también
las ventajas de una lista, ya que se puede agregar elementos al final sin restriccio-
nes de espacio (naturalmente la memoria del computador no es infinita y por lo
tanto si hay limitaciones).
Vamos a reemplazar el arreglo arr, en la clase Juego, por un ArrayList.
Veamos:

import java . u t i l . ArrayList ;


2
p u b l i c c l a s s Juego
4 {
A r r a y L i s t <Monstruo > a r r ;
6
public Juego ( ) {
8 arr = new A r r a y L i s t < >() ;
arr . add ( new Orco ( ” Garnag ” , 1 0 , ” g a r r ” ) ) ;
10 arr . add ( new Dragon ( ” B r e n t o n ” , 2 0 , ” m e t a l ” ) ) ;
arr . add ( new Orco ( ” Rogthun ” , 5 , ” p u r r ” ) ) ;
12 arr . add ( new Dragon ( ” Draco ” , 4 0 , ” c u e r o ” ) ) ;
}
14
p u b l i c v o i d a g r e g a r M o n s t r u o ( M o n s t r u o m) {
16 a r r . add (m) ;
}
18
p u b l i c void moverMonstruos ( ) {

12
20 f o r ( M o n s t r u o m: a r r ) {
m. m o v e r s e ( ) ;
22 }
}
24
}

Hay varios cambios importantes. Primero, notar que es necesario incluir la


librerı́a correspondiente al principio del programa.
Segundo, notar la sintaxis para declarar a inicializar un ArrayList. Tercero,
ver el código del método agregarMonstruo. Simplemente se añade un monstruo.
Java se encarga de que no falte espacio. Cuarto, notar la sintaxis para recorrer un
ArrayList, en el método moverMonstruos().

Ejercicio 15. Notar que BlueJ no cambia la representación gráfica si en la clase


B se tiene una sola referencia a un objeto del tipo C o si se tienen muchas refe-
rencias (como en el caso de un ArrayList). Consultar cómo se exrpesa en UML el
hecho de que en la clase B haya 0 o muchas referencias a instancias de la clase C.
Ver por ejemplo: [6]

3.3. Clases abstractas


Los monstruos de nuestro juego son los orcos y los dragones. La clase Mons-
truo sirve para manejar los aspectos comunes a ambos. Pero no debemos permitir
instanciar objetos de la clase Monstruo (no tendrı́a identidad). Para evitar que esto
ocurra, declaramos que la clase Monstruo es abstracta. El encabezado queda de la
siguiente manera:
public abstract class Monstruo

Ejercicio 16. ¿Qué ocurre ahora si se trata de hacer una instancia de la clase
Monstruo? Explique con sus palabras.

3.4. Otros ejemplos de polimorfismo


Ahora que conocemos bien cómo manejar la herencia el polimorfismo, pode-
mos implementar los siguientes problemas:

13
Ejercicio 17. Implementar dos clases derivadas de la clase Humano. Una será
un jugador normal y la otra será un NPC (non-playable character). Definir al-
gunos atributos comunes que se manejarán en la clase Humano y otros que se
manejarán en cada clase derivada. Crear un método común en la clase Humano
que permita implementar un ejemplo de polimorfismo desde la clase Juego. Las
referencias a los humanos de manejarán en un ArrayList desde la clase Juego.

Ejercicio 18. Implementar dos tipos de armas. Una será para combate de con-
tacto y la otra para un rango de distancia. El jugador podrá tener 0 o muchas armas.
Lo anterior se representará como un ArrayList de armas en la clase Jugador. Im-
plementar algún ejemplo de polimorfismo entre la clase Jugador y la clase Arma.

Ejercicio 19. Crear una clase Tablero como una matriz de celdas. Cada celda
puede contener un Monstruo o un Humano o estar vacı́a. El jugador puede indicar
el movimiento de su representación. Si el jugador está adyacente a un monstruo, se
atacarán mutuamente con el arma que tengan activa y se lanzará un dado (número
random) para calcular el daño, utilizando un sistema de turnos.
Nota: crear y jugar este juego puede ser adictivo. No se olvide de su vida
social.

4. Bibliografı́a
Referencias
[1] Inheritance in object oriented programming. https://en.wikipedia.
org/wiki/Inheritance_(object-oriented_programming). Accessed:
2020-04-27.

[2] Java 8. api documentation arraylist. https://docs.oracle.com/javase/


8/docs/api/java/util/ArrayList.html. Accessed: 2020-04-27.

[3] Object oriented programming. https://medium.com/@rogercodes1/


what-is-object-oriented-programming-88a18d9ec7c. Accessed:
2020-04-27.

[4] polymorphism. https://www.webopedia.com/TERM/P/polymorphism.


html). Accessed: 2020-04-27.

14
[5] Rol-playing game. https://en.wikipedia.org/wiki/Role-playing_
video_game). Accessed: 2020-04-27.

[6] Uml class diagram relationships explained with examples. https:


//creately.com/blog/diagrams/class-diagram-relationships/).
Accessed: 2020-04-27.

15

También podría gustarte