0% encontró este documento útil (0 votos)
10 vistas284 páginas

Capitulo2POOEnJava

El documento aborda la programación orientada a objetos en Java, destacando conceptos clave como objetos, clases, encapsulación, abstracción y modularidad. Se discuten ejemplos de modelos de dominio y relaciones entre conceptos, así como la importancia de identificar entidades, atributos y restricciones en el desarrollo de software. Además, se presentan ejercicios prácticos para aplicar estos conceptos en contextos reales.

Cargado por

gonzalo.marchant
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
10 vistas284 páginas

Capitulo2POOEnJava

El documento aborda la programación orientada a objetos en Java, destacando conceptos clave como objetos, clases, encapsulación, abstracción y modularidad. Se discuten ejemplos de modelos de dominio y relaciones entre conceptos, así como la importancia de identificar entidades, atributos y restricciones en el desarrollo de software. Además, se presentan ejercicios prácticos para aplicar estos conceptos en contextos reales.

Cargado por

gonzalo.marchant
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 284

2.

1
CAPÍTULO II: PROGRAMACIÓN ORIENTADA AL
OBJETO CON JAVA

2.1. Aproximación a la orientación al objeto

Se trata de resolver problemas, identificando los objetos asociados con el


problema y convirtiéndolos en objetos del programa.

Por ejemplo, son objetos:


José García
Compañía ABC S.A.
Lassie
Proceso Número 7468

Un objeto es, sencillamente, algo que tiene sentido en el contexto de la


aplicación.
Un objeto tiene estado, exhibe una conducta bien definida y tiene una
identidad única.
Ejemplo del objeto martillo
2.2
Algunos conceptos asociados en la orientación al objeto

 Abstracción: Se enfoca en las características esenciales de algún objeto,


relativa a la perspectiva de quien mira al objeto.

 Encapsulación: Oculta los detalles de la implementación de un objeto.


2.3
Para la encapsulación se deben respetar los siguientes puntos:
 La abstracción de un objeto debería preceder a las decisiones sobre su
implementación.
 Una vez que se ha seleccionado la implementación, debe tratarse como
un secreto de la abstracción, oculto para la mayoría de los clientes.
 Ninguna parte de un sistema complejo debe depender de los detalles
internos de otras partes.

El elemento de la abstracción es la clase.

 Modularidad:
Permite subdividir una aplicación en partes más pequeñas (llamados
módulos), cada una de las cuales debe ser tan independientes como sea
posible de la aplicación en sí y de las restantes partes.

La modularización consiste en dividir un programa en módulos que se


puedan compilar por separado, pero que tienen conexiones con otros
módulos.

La modularidad es la propiedad de un sistema que permite su


descomposición en un conjunto de módulos cohesivos y débilmente
acoplados.

La modularidad empaqueta las abstracciones en unidades discretas.

En el caso de Java se hace a través de los paquetes.

Por lo tanto, una aplicación en Java queda formada por código que está en
distintos paquetes y cada paquete puede tener varios archivos con
extensión .java
2.4

Una ventaja de utilizar la orientación al objeto es que se minimiza la brecha


semántica, ya que los objetos de la realidad son directamente mapeados en
objetos en el modelo.

Diferencia semántica entre la realidad y el modelo


Realidad
Casa Auto
Tom Árbol

Brecha
Semántica

Casa Auto
Vive en Conduce
Modelo un Árbol
Tom
2.5
En la etapa de análisis aparecen los objetos del dominio del problema, es
decir, los objetos del mundo real.

Cuando se especifica la solución, aparecen nuevos objetos, desde el punto de


vista de la solución del problema.

Capas de especificaciones de objetos resultantes del


proceso de refinamiento

¿Qué? Dominio del problema


Objetos definidos durante
el análisis

Especificación de la
solución
Objetos definidos durante el
diseño

¿Cómo?
2.6
2.2. Modelo del dominio

 “Un modelo de dominio es una representación de conceptos en un


dominio del problema” [MO95, Fowler96]

 “El modelo de dominio representa las “cosas” que existen o eventos que
transcurren en el entorno de un negocio.” [I. Jacobsen]

Ejemplos de modelo del dominio

Ejemplo 1 La flecha representa en qué


dirección se lee el verbo
tiene
Persona Compañia
nombre 1..* 1 nombre
apellido
salario
1
propietario <<Regla>>
Si una persona no es empleado
de una compañía, ésta no
* puede ser propietario de una
Camioneta camioneta
patente
marca
año
2.7

Relacionamientos entre conceptos

Concepto de relacionamiento

El relacionamiento entre conceptos es una asociación natural en el contexto


del problema

Ejemplo
Para un problema dado, se pueden efectuar las siguientes aseveraciones:
 Un cliente coloca cero o más ordenes de compra.
 Una orden de compra es colocada por uno y sólo un cliente.

“1 y sólo 1” “Cero o más”

1 Coloca *
Cliente Orden

 La línea entre las clases muestra el relacionamiento.

 El verbo describe el relacionamiento.

 Notar que todos los relacionamientos son bidireccionales, en forma


implícita, indicando con ello que pueden ser interpretados en ambas
direcciones.
2.8
Multiplicidad del relacionamiento
La multiplicidad define el mínimo y el máximo número de ocurrencias de un
concepto asociados a una única ocurrencia del concepto relacionado.

Debido a que todos los relacionamientos son bidireccionales, la


multiplicidad debe ser definida en ambas direcciones, para cada
relacionamiento.

Tipos de multiplicidad

La multiplicidad define cuántas instancias de un concepto A pueden


asociarse a un concepto B.

1
Concepto 1 y sólo 1

* Concepto 0 ó más

n..m
Concepto
Entre n y m
2.9

1..*
Concepto 1 o más

3,5,8
Concepto Exactamente 3, 5
u ocho

5
Concepto Exactamente 5

Ejemplos

1..* pertenece 1
Profesor Depto

1..2 dicta 0..4


Profesor Asignatura

1..* pertenece 1
Estudiante Carrera

0..1 se le ha prestado 1..3


Estudiante Libro
2.10
Características del modelo del dominio

 Concepto: Denota un tipo de objeto.

 Atributos: Describen un conjunto de valores asociados a un concepto.

 Asociaciones: Representa cómo dos o más conceptos se encuentran


vinculados.

 Reglas adicionales: Se describen mediante notas las reglas que no


pueden ser representadas por la simbología.

Concepto. Los tipos de conceptos pueden ser:


 Objetos de negocio: Representa cosas que son manipuladas en un
negocio. (Ej: Boleta)
 Objetos del mundo real: Cosas que la empresa realiza un seguimiento.
(Personas, Sitios)
 Eventos que transcurren: Venta y pagos.

Recomendaciones para el Modelo del Dominio


 Listar los conceptos idóneos
 Dibujar los conceptos en un modelo de dominio
 Incorporar las asociaciones necesarias
 Agregar atributos necesarios

 ¿Cómo identificar Conceptos?


 Sustantivos y frases en descripción textual del dominio
 ¿Cómo identificar Atributos?
 Concepto que puede ser representado por un número o un texto.
2.11

Caso de Estudio: Modelo del dominio


 Desarrollar un modelo de dominio que permita modelar el
requerimiento de la Farmacia “Dr Pepito”.
 La Farmacia “Dr Pepito” requiere de un software que le permita
administrar venta de medicamentos.
 El software debe considerar los siguientes aspectos:
 Algunos medicamentos sólo pueden ser vendidos bajo receta
medica, o en su defecto, con la aprobación del farmacéutico.
 Los vendedores deberán registrar los remedios que se compren en
un TPV, en donde se ingresará el código del remedio, cantidad y
% de descuento.
 Al finalizar la venta, los clientes podrán cancelar los remedios en
efectivo, tarjeta o cheque al día.
 Al terminar el pago, el vendedor le entrega los productos al
cliente junto con el comprobante de pago.
2.12
Conceptos

Medicamento

Comprobante de pago
2.13
Asociaciones

1..* 1..* 0..*

Medicamento 1..* Comprobante de pago

1..*

1..*

1..* 1..*
2.14
Atributos

nombre rut
dirección

rut

1..* 1..* 0..*

Medicamento contiene Comprobante de pago


1..*
identificador
código 1..* fecha
total

1..*
1..*
1..*
tipo

rut
2.15
 El Modelo del Dominio se obtiene identificando:
1. Entidades
a. Nombre
b. Propiedades o características
2. Relaciones
a. Nombre
b. Dirección
c. Cardinalidad
3. Restricciones

 El objetivo es que lo entienda el cliente

 No se necesita colocar el tipo de los atributos. El cliente no sabe de


eso

Problema Tutores
En los últimos años la Universidad Católica del Norte se ha preocupado
por el rendimiento de sus alumnos y ha puesto en marcha el plan piloto
“Tutores” en algunas carreras específicas. Cómo el número de carreras ha
sido pequeño, toda la información del plan ha sido realizada a mano hasta
el momento. El plan ha dado como resultado una mejora superior a lo
esperado, es por ello, que la UCN ha decidido expandir el plan al resto de
los alumnos.
2.16
Modelo del Dominio

Area de especialización
2.17
Modelo del Dominio

Area de especialización

Alumno tutelado

asiste
Alumno tutor
2.18
Modelo del Dominio

Area de especialización

Alumno tutelado
tutelado

asiste
Alumno tutor
2.19
Modelo del Dominio
¿Tiene restricciones?, ¿Cuáles?

Restriciones Tutores
 Nombre del alumno no puede ser inferior a 2 letras.
 Rut del alumno debe ser válido.
 Nota de enseñanza media debe estar en el intervalo 1.0 – 7.0. Se
aceptan las notas con un dígito decimal.
 Puntaje de ingreso debe ser un valor entero entre 500 y 900 puntos.
 Semestre que cursa debe ser un valor entre 1 y 14.
 Un alumno sólo puede ser tutor si ha cursado a lo menos dos
semestres de su carrera y posee menos de cinco asignaturas inscritas
en el semestre.
 …
Operaciones en el modelo del dominio
En el modelo del dominio se pueden colocar operaciones cuando éstas
son parte del modelo del negocio y son calculables. A este nivel, en el
análisis se está preocuado de los conceptos, atributos y relacionamientos y
normalmente no estamos preocupados de identificar las operaciones

Operaciones Tutores
 Obtener la cantidad de horas en que el tutor realizó la tutela.
 Calcular el incentivo que le corresponde.
2.20
Modelo del Dominio + Operaciones

asiste

Calcular horas()
Calcular incentivo()
2.21
Ejercicio
Se debe construir una aplicación maneje los proyectos en los que trabaja
un empleado. En un proyecto trabajan muchos empleados y un empleado
puede trabajar en varios proyectos. Es importante saber cuántas horas a la
semana le dedica cada empleado a cada uno de los proyectos en que
trabaja .

Construya el modelo del dominio

* trabajan 1..*
Proyecto Empleado
Código proyecto Rut empleado
Nombre proyecto Nombre empleado
Dedicacion
horas a la semana

Otra forma

Proyecto tiene tiene Empleado


Código 1 1 rut
Nombre Nombre

1..* *
Dedicacion
horas
2.22
Ejercicio
Se debe construir una aplicación para que el jefe de carrera de ICCI pueda
inscribirle a los estudiantes de la carrera las asignaturas de un determinado
semestre. Para esto el jefe de carrera atiende a cada uno de los estudiantes
en su oficina, utilizando la aplicación para la inscripción. Cabe señalar que
cuando el jefe de carrera le inscribe una asignatura a un estudiante, debe
indicar en qué oportunidad la está inscribiendo. De una asignatura interesa
el código, nombre y créditos. De un estudiante, su rut y nombre. Esta
aplicación tendrá como usuario solo al jefe de carrera.
Construya el modelo del dominio
1..* inscribe 1..*
Estudiante Asignatura
nombre codigo
rut nombre
Inscripcion creditos
oportunidad
*
Jefe de Carrera ICCI
1
realiza

Otra forma
Estudiante
1 Asignatura
tiene tiene
Rut 1
Código
Nombre Nombre
Créditos
1..* 1..*
realiza Inscripcion
Jefe de Carrera 1 Oportunidad
*
2.23
2.3. Conceptos de orientación al objeto
2.3.1. Cinco palabras claves del vocabulario O.O

Objeto: Colección de datos privados y operaciones públicas.

Clase: Descripción de un conjunto de objetos con propiedades


(atributos) similares, con relaciones comunes con otros
y con una semántica común.

Instancia: Es un objeto de esa clase.

Método: Un cuerpo de procedimiento que implementa una


operación.

Mensaje: Un llamado a un procedimiento. Un requerimiento


para ejecutar un método.

Ejemplo:
 Clase con sus atributos:

Persona
nombre: String
edad : int
2.24
 Objetos con sus valores
p1: Persona p2: Persona

nombre = Juan García nombre = María Perez


edad = 24 edad = 40

Objeto:

 Colección de campos, junto a una colección de operaciones (llamados


métodos) que operan en los campos.

 Un objeto encapsula los componentes pasivos (campos) y los


componentes activos (métodos) en una única entidad.

 Este encapsulamiento incrementa la modularidad del programa: al aislar


un objeto del resto del programa, se obtiene un programa que es más
fácil de entender y de modificar.

 El estado de un objeto, es representado por un conjunto de atributos.

 Los atributos mantienen información acerca de un objeto.

 El comportamiento de un objeto, representa las acciones que pueden


ser realizadas sobre el objeto.

 Estas acciones ocurren cuando un mensaje es enviado hacia el objeto.


2.25
Clase:
 Todos los tipos que no son primitivos son CLASES

 Una clase es un conjunto de objetos que comparten una estructura


común y un comportamiento común.

 Un objeto particular es simplemente una instancia de una clase.

 Un objeto no es una clase.

 ¡ Una clase puede ser un objeto ! (Por lo tanto, a la clase se le puede


enviar un mensaje, por ejemplo, new)

Ejemplos de Clases:
 Puerta Para una empresa que fabrica puertas y ventanas
 Empleado Para un sistema de remuneraciones
 Habitación Para un sistema de reservas de un hotel
 Vehículo Para un sistema de arriendo de vehículos

Ejemplos de Atributos:
 Puerta largo
ancho
espesor
tipo de madera
2.26
 Empleado rut
nombre
dirección particular
fono particular
fono empresa

 Habitación número
cantidad de camas
metros cuadrados
citófono
valor

 Vehículo patente
marca
modelo
año

Ejemplo de Comportamiento:
 Puerta abrir
cerrar
poner llave
sacar llave
2.27
Ejercicio
Se tiene que hacer un programa que maneje información de los alumnos y
profesores de la UCN. Identifique las clases e indique para ellas atributos y
comportamiento. Muestre para cada una de las clases identificadas, 2
ejemplos de objetos.

Alumno Profesor
numeroMatricula: String nombre: String
nombre: String tipo: int
edad : int

getNumeroMatricula(): String getNombre(): String

a1: Alumno a2: Alumno p1: Profesor p2: Profesor


numeroMatricula = 111 numeroMatricula = 222 nombre = Raúl Vega nombre = Pedro Soto
nombre = Juan García nombre = Juan Perez tipo = 1 tipo = 2
edad = 24 edad = 19
2.28
2.3.2. Interface, implementación y diagrama de una clase

Interface de una clase


 La interface de una clase proporciona su vista externa y por lo tanto
enfatiza la abstracción, mientras esconde su estructura y los secretos de su
comportamiento.

 En un nivel abstracto, una clase es una interface que define la conducta de


sus objetos

Las operaciones, o funciones e interfaces,


proporcionan un canal de comunicación hacia
y desde el objeto de la clase.

requerimiento de la operación Caja negra del


Programa de objeto de la
resultado de la operación
Aplicación clase

Implementación de una clase


 La implementación de una clase corresponde a su vista interna, la que
abarca los secretos de su comportamiento.
 La implementación de una clase consiste principalmente de la
implementación de todas las operaciones definidas en la interface de la
clase.
 Algunas de las visibilidades en una clase:
 PUBLIC
 PRIVATE
2.29
 PUBLIC: Es una declaración que está visible a todos los clientes.

 PRIVATE: Es una declaración que está visible solamente a la misma


clase.

Diagrama de clase
A diferencia del modelo del dominio, el Diagrama de Clases es para el
diseñador del software
Nombre de Clase
Visibilidad tipo de dato 1 nombre atributo 1
Visibilidad tipo de dato 2 nombre atributo 2
...

Visibilidad nombre operación 1 (lista argum.1): tipo de resultado 1

Visibilidad nombre operación 2 (lista argum.2): tipo de resultado 2


...

Ejemplo:
Persona
- private - String nombre
+ public - int edad
+ Persona(String nom, int edad)
+ getEdad(): int
+ getNombre(): String
+ setEdad(int edad)
+ setNombre(String nombre)
2.30
2.3.3. Variables y Métodos de Instancia, Variables y Métodos de Clase

Problema: Se debe manejar información de cuentas de ahorra. De cada


cuenta se tiene un número y saldo. Se sabe además que a todas las cuentas se
les otorga el mismo interés.

Variable de Instancia:
 Una variable de instancia pertenece a una instancia. Su valor sólo
puede ser cambiado por operaciones que pertenecen a la instancia.

 Existe tanto como lo hace la instancia, es decir, la existencia de la


variable de instancia depende de la existencia del objeto que la contiene.

Variable de Clase:
 Variable compartida por todas las instancias de una clase (una ÚNICA
copia).
 Todos los objetos de la clase la pueden ver.

CuentaAhorro
Variable de instancia
- int numero Cada objeto tiene su
- int saldo número y saldo
- $ double interes

Variable de clase
Todas las instancias ven el
interés. Es el mismo para
todos los objetos
2.31
Métodos de instancia:
 Pertenece a un objeto.

Métodos de clase:
 Está asociado a una clase.

Ejemplo:

Variables de instancia

CuentaAhorro
Variable de clase
- int numero
- int saldo
- $ double interes
Método de instancia
+ getNumero(): int
+ $ getInteres(): double
Método de clase

Forma de invocación:
 c.getNumero() c es un objeto de la clase CuentaAhorro

 CuentaAhorro.getInteres()
2.32
2.3.4. Operaciones sobre un objeto

En la práctica se ha encontrado que un cliente realiza típicamente cinco tipos


de operaciones sobre un objeto:

 Modificador
 Obtenedor
 Constructor
 Destructor

Modificador: Es una operación que altera el estado de un objeto


(Métodos set).

Obtenedor: Es una operación que accesa al estado de un objeto,


pero no lo altera (Métodos get).

Constructor: Es una operación que crea un objeto y/o inicializa


su estado.

Destructor: Es una operación que libera el estado de un objeto


y/o destruye el objeto mismo.
2.33
2.3.5. Declaración, creación, asignación, comparación y
destrucción de objetos

A. Declaración del objeto

NombreClase nombreVariable;

La declaración no establece almacenamiento para la variable.


Ejemplo: Persona p;

B. Creación de objetos
Un objeto en JAVA, se construye únicamente por la expresión de creación
dinámica, que tiene la forma:

new NombreClase (parámetros_actuales);


Ejemplo: new Persona (25);

La evaluación de esta expresión significa:


a) Asignación de memoria para un nuevo objeto de la clase
NombreClase, asociándole valores iniciales a las variables del objeto.
b) Se invoca el constructor apropiado de la clase, con los parámetros
correspondientes.
c) Se regresa como resultado la referencia al objeto creado.

Si no hay rutina constructora, existe un constructor por defecto que crea el


espacio y coloca los valores por defecto para los atributos de la clase.
2.34
C. Asignación de Objetos
Para tipos primitivos
int x = 5;
int y = 1;
x = y;
x y
5 1 1

Ejemplo: miObjeto = tuObjeto;

“Shallow Copy” o Copia Superficial

Nuevo almacenamiento no es creado para el objeto destino, en la


asignación de objetos.
Persona p1, p2
p2 = new Persona(25);
p1 = p2
p1 p2

D. Comparación de Objetos

Los operadores == (igual) y != (no igual) se utilizan para comparar


expresiones cuyos valores son referencias a objetos.

Esta comparación prueba si al evaluar las dos expresiones, el resultado es


o no, la referencia al mismo objeto (identidad versus igualdad).

Semántica por referencia (Reference Semantics)


Las variables de tipo objeto almacenan referencias al objeto. Los objetos
en JAVA, tienen una “Semántica por Referencia”. Es decir, ellos son
realmente referencias.
2.35
Ejemplo: x, y son objetos de una clase
a b
x = y; x e y referencian
x y if (x = = y) verdadero al mismo objeto

Ejemplo de identidad:

String x = "a"; if (x == y)  falso


String y = "a"; if (x.equals(y))  verdadero
a a

x y

String x = "a";
String y = "a"; a
x = y; if ( x == y)  true

x y

Ejemplo de igualdad con tipos primitivos:

int x, y
x y
if (x = = y)  verdadero
5 5

E. Destrucción de objetos
En Java no existe el concepto de destructor explícito de objetos.

La recuperación de memoria de los objetos, que ya no son útiles, se realiza


automáticamente por el proceso recolector de basura, el cual se ejecuta de
manera paralela con el programa en Java.
2.36
Ejemplo:

Alumno
- String nombre
- String rut

+ Alumno(String nom, String rut)


+ getNombre(): String En el diagrama de
+ getRut(): String clases, los métodos
+ setNombre(String nombre) deben ir con sus
+ setRut(String rut) parámetros
+ toString(): String

No todo atributo debe tener el


A toda clase se
le puede
método set, por ejemplo, para el
colocar el número de matrícula.
método En general, si en la aplicación no
toString() existe la posibilidad de cambiar el
valor de un atributo, no es necesario
el set.
2.37

public class Alumno {

private String nombre;


private String rut;

public Alumno(String nom, String rut1) {


nombre = nom;
rut=rut1;
}

public String getNombre() {


return nombre;
}

public void setNombre(String nom) {


nombre = nom;
}

public String getRut() {


return rut;
}

public void setNumeroMatricula(String rut1) {


rut=rut1;
}

@Override
public String toString() {
return "Alumno [nombre=" + nombre + ", numeroMatricula=" +
numeroMatricula + "]";
}
}
2.38
Ejemplo de programa en Java
Se desea manejar la información de las cuentas bancarias de un banco. Una
cuenta tiene un saldo. Se puede depositar y girar sobre la cuenta bancaria.
La aplicación debe hacer un depósito sobre una cuenta y luego un giro sobre
la misma cuenta. Una vez hechas las transacciones sobre la cuenta, se debe
desplegar su saldo. Considere que la cuenta se crea inicialmente con un saldo
cero y luego se debe leer un valor desde pantalla que corresponderá al saldo
de la cuenta

Diagrama de clases
CuentaBancaria Nombre de la Clase
- int saldo Variable de Instancia
+ CuentaBancaria(int saldoInicial)
+ depositar(int cantidad)
+ girar(int cantidad): boolean
+ getSaldo(): int Métodos de Instancia
+ setSaldo(int saldoNuevo)
+ toString(): String

La clase CuentaBancaria podría también tener otros atributos

public class CuentaBancaria {

private int saldo;

public CuentaBancaria(int saldoInicial) {


saldo = saldoInicial;
}

public int getSaldo() {


return saldo;
}
2.39

public void setSaldo(int saldoNuevo) {


saldo = saldoNuevo;
}

@Override
public String toString() {
return "CuentaBancaria [saldo=" + saldo + "]";
}

public void depositar(int cantidad){


saldo = saldo + cantidad;
}

public boolean girar(int cantidad){


if (saldo >= cantidad){
saldo = saldo - cantidad;
return true;
}
else {
return false;
}
}

}//Fin cuentaBancaria
2.40

import ucn.StdOut;

public class BankApp {

public static void main(String[] args) {


//Crea una cuenta
CuentaBancaria cuentaBancaria = new CuentaBancaria(0);
StdOut.print ("Ingrese saldo: ");
int saldo = StdIn.readInt();
if(saldo >= 0){
cuentaBancaria.setSaldo(saldo);
StdOut.println("Saldo antes de las transacciones: "
+cuentaBancaria.getSaldo());
StdOut.println("Cuenta bancaria antes de las
transacciones: "+ cuentaBancaria.toString());

cuentaBancaria.depositar(74); // efectuar un depósito


cuentaBancaria.girar(20); // efectuar un retiro

StdOut.println("Despues de las transacciones: " +


cuentaBancaria.getSaldo());
StdOut.println("Cuenta bancaria despues de las
transacciones: " + cuentaBancaria.toString());
}
else{
StdOut.println("dato ingresado es incorrecto" );
}
}//fin main Recuerde que la cantidad a depositar o que se gira debe ser mayor
}//Fin BankApp que cero. Esa validación también debe hacerse en la App

Se imprime
Saldo antes de las transacciones: 100
Cuenta bancaria antes de las transacciones:CuentaBancaria [saldo=100]
Despues de las transacciones: 154
Cuenta bancaria despues de las transacciones: CuentaBancaria [saldo=154]

cuentaBancaria: CuentaBancaria
saldo = 0
Diagrama de 100
objetos 174
154
2.41
Ejercicio
Dado el siguiente diagrama de clases, complételo y escriba en Java la clase
Asignatura y un programa Java que cree un objeto Asignatura cuyo código
es “cc 571” y créditos = 14. Una vez creado el objeto se debe desplegar por
pantalla sus datos.

Asignatura
codigo
creditos
Asignatura()
getCodigo()
getCreditos()
setCodigo() No todo atributo
setCreditos() debe tener el
método set

Solución

Asignatura
- String codigo
- int creditos
+ Asignatura(String cod, int cred)
+ getCodigo(): String
+ getCreditos(): int
+ setCodigo(String cod)
+ setCreditos(int cred)
2.42
public class Asignatura {
private String codigo;
private int creditos;

public Asignatura(String cod, int cred) {


codigo = cod;
creditos = cred;
}
public String getCodigo() {
return codigo;
}
public int getCreditos() {
return creditos;
}
public void setCodigo(String cod) {
codigo = cod;
}
public void setCreditos(int cred) {
creditos = cred;
}

} Podríamos tener el método toString()

public class App {


public static void main (String [ ] args) {
Asignatura asignatura = new Asignatura (“cc 571”, 14);
StdOut.println(“Datos de la asignatura: Codigo = ” +
asignatura.getCodigo() + “ creditos= ” +
asignatura.getCreditos());
}
}
2.43
Notas:
 La rutina constructora no tiene un tipo asociado al resultado, debido a
que retorna el objeto.
 Los parámetros en JAVA son sólo traspaso por valor.

Ejemplo
El programa siguiente, crea dos objetos Punto diferentes y pone valores
únicos en cada uno.
Recuerde que si no hay rutina
public class Punto { constructora, existe un constructor
private int x; por defecto que crea el espacio y
coloca los valores por defecto para
private int y;
los atributos de la clase.
public void init (int xx, int yy) {
x = xx;
y = yy;
}
public void setX(int xx){
x = xx;
}
Punto
public void setY(int yy){
y = yy; - int x
} - int y
public int getX(){
return x; + setX(int xx)
} + setY(int yy)
public int getY(){ + getX(): int
return y; + getY(): int
}
} Podríamos tener el método toString()
2.44
public class DosPuntos {

public static void main(String args[]) {


Punto p1 = new Punto();
Punto p2 = new Punto();

p1.setX(10);
p1.setY(20);

p2.setX(42);
p2.setY(99);

StdOut.println ("x = " + p1.getX() + " y = " + p1.getY());


StdOut.println ("x = " + p2.getX() + " y = " + p2.getY());

Punto p3 = new Punto();


Punto p4 = new Punto();

p3.init(10, 20);
p4.init(42, 99);

StdOut.println ("x = " + p3.getX() + " y = " + p4.getY());


StdOut.println ("x = " + p3.getX() + " y = " + p4.getY());
}
}
2.45

p1: Punto p2: Punto p3: Punto p4: Punto

x = 0 10 x = 0 42 x = 10 x = 42
y = 0 20 y = 0 99 y = 20 y = 99

Imprime
x = 10 y = 20
x = 42 y = 99
x = 10 y = 20
x = 42 y = 99
2.46

2.3.6. Mensajes a THIS

 Dentro de la implementación de un método, el identificador this


representa una variable implícita, que referencia al objeto para el cual el
método fue invocado.

 “Un mensaje a this, es un mensaje al mismo objeto”

Ejemplo 1:
Inicializar las variables de una clase, utilizando el constructor.

public class Punto {


private int x;
private int y;
Punto
public Punto(int x, int y) {
this.x = x; - int x
this.y = y; - int y
}
public int getX(){ + Punto(int x, int y)
return this.x; + getX(): int
} + getY(): int
public int getY(){ + set…..
return this.y;
}
//…Métodos set
}
2.47
public class CrearPunto {
public static void main(String args[]){
Punto punto = new Punto(10, 20);
StdOut.println("x = " + punto.getX() + " y = " + punto.getY());
}
}

Ejemplo 2:

Empleado

+ calcSueldoTotal(): int SueldoFinal =


+ calcDescuentoTotal(): int this.calcSueldoTotal() –
+ calcSueldoFinal(): int this.calcDescuentoTotal();
2.48
2.3.7. Sobrecarga de métodos

Ejemplo 1: En la clase Punto se necesita un método para calcular la distancia entre 2


puntos. La idea es que si p1 y p2 son objetos de la clase Punto, se pueda saber cuál es
la distancia entre esos 2 puntos. Para obtener dicha distancia usaremos el método
distancia y lo invocaremos de las siguiente manera:

Punto p1 = new Punto (5,3);


Punto p2 = newPunto (8,2);

//Se quiere obtener la distancia entre p1 y p2


double distancia =p1.distancia(p2);

También podría darse el caso de querer calcular la distancia


entre un punto p1 y otro del cual se saben sus coordenadas.
Por ejemplo:

Punto p1 = new Punto (5,3);


Punto p2 = newPunto (8,2);

//Se quiere obtener la distancia entre p1 y p2


double distancia =p1.distancia(2,6);

Por lo tanto la clase Punto debe tener 2 versiones del método distancia:
 Una que tiene como parámetro un objeto de la calse Punto
 Una que tiene como parámetro 2 valores enteros que representan las coordenadas
de un punto
Punto
- int x
- int y
+ Punto(int x, int y)
+ setX(int x)
+ setY(int y)
+ getX(): int
+ getY(): int
+ distancia(int x, int y): double
+ distancia(Punto p): double
2.49
public class Punto {
private int x;
private int y;

public Punto(int x, int y) {


this.x = x;
this.y = y;
}
public int getX(){
En el diagrama de clases, se deben colocar
return x; todas las versiones de los métodos
} sobrecargados. Se diferencian por los
public int getY(){ parámetros
return y;
}
//….Métodos set

public double distancia(int x, int y) { En el ejemplo se utiliza el


int dx = this.x - x; método estático sqrt de la clase
int dy = this.y - y; Math para calcular la raíz
return Math.sqrt(dx*dx + dy*dy); cuadrada de su parámetro.
}

public double distancia(Punto p) {


return this.distancia(p.x, p.y);
}
}

public class PointDist {

public static void main (String args[]) { p1: Punto


Punto p1 = new Punto(0, 0); x=0
Punto p2 = new Punto(30, 40); y=0
StdOut.println("p1 = " + p1.getX() + ", " + p1.getY()); p2: Punto
StdOut.println("p2 = " + p2.getX() + ", " + p2.getY()); x = 30
y = 40
StdOut.println("p1.distancia(p2) = " + p1.distancia(p2));
StdOut.println("p1.distancia(60, 80) = " + p1.distancia(60, 80));
}
}
2.50

Ejemplo 2: Un constructor llama a otro constructor, para construir la instancia.


public class Punto {
private int x;
private int y;
public Punto(int x, int y) {
this.x = x;
this.y = y;
}
public Punto() {
this(-1, -1); //this.Punto(-1,-1);
}
}

Ejemplo 3: Versión de la clase Punto que utiliza la sobrecarga de método para crear
un constructor alternativo que establece algunos valores por omisión para las
coordenadas x e y.
public class Punto {
private int x;
private int y;
public Punto(int x, int y) {
this.x = x;
this.y = y;
}
public Punto() {
x = -1;
y = -1;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}

public class PointCreateAlt {


public static void main(String args[]) {
Punto p = new Punto();
StdOut.println("x = " + p.getX() + " y = " + p.getY());
}
}
2.51
2.4. Relacionamientos entre Clases/Objetos

2.4.1. Concepto de relacionamiento (Asociación)

Conceptualmente, los objetos y las clases no existen aisladas.

El relacionamiento entre clases/objetos es una asociación natural en el


problema que existe entre uno o más objetos/clases.

Ejemplo
Para un problema dado, se pueden efectuar las siguientes aseveraciones:
 Un cliente coloca cero o más ordenes de compra.
 Una orden de compra es colocada por uno y sólo un cliente.

“1 y sólo 1” “Cero o más”

1 *
Cliente Orden

 La línea entre las clases muestra el relacionamiento.

2.4.2. Multiplicidad del relacionamiento

Igual que en el modelo del dominio


2.52
Tipos de multiplicidad
1 Clase 1 y sólo 1

* Clase 0 ó más

n..m
Clase Entre n y m

2.4.3. Agregación y composición

Agregación Composición
Independencia Dependencia
Tiene-un Parte-de
Débil Fuerte

Existe en Java No existe en Java

a. Agregación
Una clase especial de relacionamiento puede existir entre objetos / clases:

 Algunas veces los objetos / clases están formados por otros objetos.

 Un objeto tiene otros objetos.

 Este tipo especial de relacionamiento se llama agregación.

 Un objeto es fabricado con otros objetos.


2.53
Ejemplos:

Auto:
 Transmisión
 Tubo de escape
 Motor
 Suspensión
 Ruedas

Ventana:
 Botones
 Labels
 Menús

Se utiliza el símbolo en un extremo del relacionamiento para indicar


la agregación.

Ejemplo 1: Computador

1 1 1 1
Monitor Caja Mouse Teclado
sistema

1 1 1 1
Chassis Cpu RAM Ventilador
2.54
Ejemplo 2: Libro

1 0..1 1..* 1
Cubierta Tabla de Capítulo Indice
contenido
s
1..*

Pagina

1..*
Párrafo

1..*

Palabra

b. Composición
A * B

Compuesto Componente

La diferencia entre composición y agregación es que en la composición si se


elimina el compuesto también se eliminan los componentes. En el caso de la
agregación no.

Resumiendo, la composición es la ASOCIACIÓN


más restrictiva, la más fuerte. En
AGREGACIÓN
cambio la asociación es la más liberal, COMPOSICIÓN
la menos restrictiva.
2.55
2.5. Contenedores implementados con arreglos
2.5.1. Clase Contenedor

Ejemplo: Se necesita una aplicación que maneje los datos de los estudiantes de la UCN, sede
Coquimbo.

En este caso debemos tener un contenedor de Estudiantes.

¿Qué caracteriza al contenedor?


 El arreglo que contiene a los estudiantes
 El tamaño máximo del contenedor. En este caso, podría ser 5000
 La cantidad de elementos del contenedor

¿Qué podemos hacer con este contenedor?


 Ingresar un estudiante
 Eliminar un estudiante
 Buscar un estudiante

ListaEstudiantes * Estudiante
- double [ ] lista - String rut
- String nombre
- int cantidadEstudiantes + Estudiante(String rut, String nombre)
- int max + get y set….
+ ListaEstudiantes(int max)
+ buscar(String rut): Estudiante
+ ingresar(Estudiante estudiante): boolean
+ eliminar(String rut): boolean
+ getCantidadEstudiantes(): int
+ getEstudiante(int i): Estudiante

¿Qué se gana con tener una clase Contenedor?


 Se mejora la interface con los clientes de la clase.
 El usuario de la clase, en este caso Contenedor, debe estar libre para concentrarse en ¿qué?,
en vez de ¿cómo?
¿Qué va a ser insertado?
¿Qué va a ser eliminado?
¿Qué va a ser accesado?, en vez de conocer ¿Cómo estas
actividades son llevadas a cabo?
 El contenedor debe tener métodos tales como: buscar, eliminar, agregar, obtener el elemento
i-ésimo del contenedor, etc.
2.56
Veamos un Contenedor de doubles
ListaDoubles
// ListaDoubles.java
- double [ ] lista
- int cantidadElementos
public class ListaDoubles { - int max
private double[] lista;
// referencia el arreglo + ListaDoubles(int max)
+ encontrar(double claveBusqueda): int
private int cantidadElementos; + insertar(double valor): boolean
// número de items + eliminar(double valor): boolean
+ getCantidadElementos(): int
private int max; + getElem (int i): double
//Máxima cantidad de elementos
//para el contenedor

public ListaDoubles(int max) {


// constructor
lista = new double[max]; //crea el arreglo
cantidadElementos = 0; //no tiene items todavía
this.max = max;
}

public int encontrar(double claveBusqueda){


// Si encuentra el valor especificado, retorna la
//posición donde lo encuentra. Sino, retorna un -1
int j;
for(j=0;j<cantidadElementos;j++) {// para cada elemento
if(lista[j]==claveBusqueda){ // ¿item encontrado?
break; // sale del for Recuerde que el break sale
} del ciclo más cercano
}
if(j == cantidadElementos){//no lo encontró
return -1;
}
else{
return j; // si lo encontró, en la posición j
}
} // end econtrar()
2.57
Alternativa para el código encontrar

public int encontrar(double claveBusqueda){


int j = 0;
while (j< cantidadElementos && lista[j]!=claveBusqueda){
//Mientras este dentro de los limites del arreglo y no
//haya encontrado lo que se está buscando
j++; //Avance a la siguiente posición del arreglo
}
if(j == cantidadElementos) { //no lo encontró
return -1;
}
else{
return j; // si lo encontró, en la posición j
}
} // end econtrar()

public boolean insertar(double valor){


//inserta elemento en el contenedor
if (cantidadElementos < max) { //Hay espacio
lista[cantidadElementos] = valor; //lo inserta
cantidadElementos ++; // incrementa el tamaño
return true;
}
else {
return false;
}
}

public int getCantidadElementos() {


return cantidadElementos;
}

public double getElem (int i) {


if (i < cantidadElementos){
return lista[i];
}
else{
return 0;
}
}
2.58
public boolean eliminar(double valor){
//Busca el elemento a eliminar
int j;
for(j=0; j< cantidadElementos; j++){
if( valor == lista[j] ) {
break;
}
}

if(j== cantidadElementos){//no lo encontró


return false;
}
else { // si lo encontró
//Corrimiento
for(int k=j; k<cantidadElementos - 1;k++){
lista[k] = lista[k+1];
}
cantidadElementos--; // decrementa tamaño
return true;
} //fin else
} // end eliminar()

} // end class ListaDoubles

Alternativa para eliminar


public boolean eliminar(double valor){
int pos=this.encontrar(valor);
//Invoca al método encontrar

if (pos != -1){
//Corrimiento
for(int k=j; k<cantidadElementos - 1;k++){
lista[k] = lista[k+1];
}
cantidadElementos--; // decrementa tamaño
return true;
}
else{
return false;
}
}
2.59
public class ListaDoublesApp {
public static void main(String[] args){
int tamMaximo = 100; // tamaño máximo
ListaDoubles ld; // referencia al arreglo
ld = new ListaDoubles(tamMaximo);//crea el contenedor
ld.insertar(77); // inserta 10 items
ld.insertar(99);
ld.insertar(44);
ld.insertar(55);
ld.insertar(22);
ld.insertar(88);
ld.insertar(11);
ld.insertar(00);
ld.insertar(66);
ld.insertar (33);
//Despliga los items del contenedor
for (int i =0; i <ld.getCantidadElementos ();i++){
StdOut.println(ld.getElemI(i));
}
int claveBusqueda = 35; // busca el item
if( ld.encontrar(claveBusqueda)!= -1){
StdOut.println("Encontrado " + claveBusqueda);
}
else {
StdOut.println("No Encontrado " + claveBusqueda);
}
ld.eliminar(00); // elimina 3 items
ld.eliminar(55);
ld.eliminar(99);
//Despliega los items del contenedor
for (int i =0; i <ld.getCantidadElementos (); i++){
StdOut.println(ld.getElemI(i));
}
} // end main()

} // end class ListaDoublesApp


2.60
Ejercicio
En el ejemplo anterior, el contenedor almacena datos de un tipo primitivo. El
siguiente ejemplo, muestra cómo guardar objetos.
* ListaPersonas
Persona
- String apellido - Persona [ ] lista
- String nombre - int cantidadPersonas
- int edad - int max
+ Persona(String apellido, String nombre, int edad)
+ getApellido():String
+ getNombre(): String + ListaPersonas(int max)
+ getEdad(): int + buscarPersona(String apellido): Persona
+ setApellido(String apellido) + ingresarPersona(Persona persona): boolean
+ setNombre(String nombre) + eliminar(String apellido): boolean
+ setEdad(int edad)
+ toString():String
+ getCantidadPersonas(): int
+ getPersonaI(int i): Persona
+ toString(): String

public class Persona {


private String apellido;
private String nombre;
private int edad;

public Persona(String apellido, String nombre, int edad) {


this.apellido = apellido;
this.nombre = nombre;
this.edad = edad;
}

public String getApellido() {


return apellido;
}

public void setApellido(String apellido) {


this.apellido = apellido;
}
2.61
public String getNombre() {
return nombre;
}

public void setNombre(String nombre) {


this.nombre = nombre;
}

public int getEdad() {


return edad;
}

public void setEdad(int edad) {


this.edad = edad;
}

@Override
public String toString() {
return "Persona [apellido=" + apellido + ", nombre=" +
nombre + ", edad=" + edad + "]";
}
}//Fin Persona

public class ListaPersonas {

private Persona []lista;


private int cantidadPersonas;
private int max;

public ListaPersonas(int max){


lista = new Persona [max];
cantidadPersonas = 0;
this.max = max;
}
2.62
public boolean ingresarPersona(Persona persona){
if (cantidadPersonas < max){
lista[cantidadPersonas]= persona;
cantidadPersonas ++;
return true;
}
else{
return false;
}
}
En el método ingresarPersona, es mejor traspasar el objeto que recibir sus
atributos y crearlo. Lo anterior, debido a que si hay un cambio en la persona
habría que intervenir este código.
Ejemplo
public boolean ingresarPersona(String nombre,String apellido,int edad){
Persona persona = new Persona (apellido, nombre, edad);
if (cantidadPersonas < max){
lista[cantidadPersonas]= persona;
cantidadPersonas ++;
return true;
}
else{
return false;
}
}

Suponga que a la persona se le agregará la dirección. En ese caso, se tendría


que arreglar este código. En cambio si el parámetro del método ingresar es el
objeto persona no se debe intervenir este método
public int getCantidadPersonas(){
return cantidadPersonas;
}

public Persona getPersonaI(int i){


if (i >=0 && i < cantidadPersonas){
return lista[i];
}
else{
return null;
}
}
2.63
public Persona buscarPersona(String apellido){
int i;
for(i = 0; i < cantidadPersonas; i++){
if (lista[i].getApellido().equals(apellido)){
break;
}
}
if (i == cantidadPersonas){
return null;
}
else{
return lista[i];
}
}
public boolean eliminar(String apellido) {
// elimina la persona del contenedor
int j;
for(j=0; j< cantidadPersonas; j++){
if(lista[j].getApellido().equals(apellido)) {
break; //sale del for
}
}
if(j== cantidadPersonas) { // no lo encontró
return false;
}
else { // lo encontró
for(int k=j;k<cantidadPersonas-1;k++){//corrimiento
lista[k] = lista[k+1];
}
cantidadPersonas --; // decrementa el tamaño
return true;
} //end else Es mejor sobreescribir
} //Fin eliminar el método toString que
se obtiene desde el
//Se obtiene un string con todos los
Eclipse o NetBeans para
//elementos de la lista
public String toString(){ un contendor.
String r = ""; Lo anterior debido a que
for (int i=0;i<cantidadPersonas;i++){ invoca toString para
r=r+lista[i].toString()+ "\n"; cada elemento y puede
} que el contedor no esté
return r; lleno y existan espacios
} nulos
}//Fin ListaPersonas
2.64

import ucn.StdOut;
public class ListaPersonasApp {
public static void desplegarPersonas(ListaPersonas
listaPersonas){
// despliega los items
StdOut.println("Despliegue de las personas");
for(int i=0; i<listaPersonas.getCantidadPersonas();i++){
Persona p = listaPersonas.getPersonaI(i);
StdOut.println(p.getApellido() + " " +
p.getNombre() + " " +p.getEdad());
}
StdOut.println();
}

public static void main(String[] args) {


int maxSize = 100; // tamaño del contenedor
ListaPersonas listaPersonas =
new ListaPersonas(maxSize);
//referencia y crea la lista

// inserta 10 items
Persona p = new Persona("Martinez", "Jose", 24);
listaPersonas.ingresarPersona(p);
Persona p9 = new Persona("Tapia","Luis",37);
listaPersonas.ingresarPersona(p9);
Persona p1 = new Persona("Viorklumds", "Jorge", 43);
listaPersonas.ingresarPersona(p1);
Persona p2 = new Persona("Ferrada", "Cecilia", 63);
listaPersonas.ingresarPersona(p2);
Persona p3 = new Persona("Vega","Carlos",21);

desplegarPersonas(listaPersonas);
StdOut.println("Despliegue de las personas");
StdOut.println(listaPersonas.toString());
StdOut.println();
2.65

StdOut.println("Buscando a Martinez");
String apellido = "Martinez"; // busca el item
Persona found=listaPersonas.buscarPersona(apellido);
if(found != null){
StdOut.print("Encontrado ");
StdOut.println(found.getApellido() + " " +
found.getNombre() +" " + found.getEdad());
}
else {
StdOut.println("No encontrado " + apellido);
}
StdOut.println();

StdOut.println("Eliminando Viorklumds, Vega y Alfaro");


// elimina 3 items
boolean pudoEliminar=listaPersonas.eliminar("Viorklumds");
if (pudoEliminar){
StdOut.println("si elimino a Viorklumds");
}
pudoEliminar =listaPersonas.eliminar("Vega");
if (pudoEliminar){
StdOut.println("si elimino a Vega");
}
pudoEliminar =listaPersonas.eliminar("Alfaro");
if (pudoEliminar){
StdOut.println("si elimino a Alfaro");
}
StdOut.println();

desplegarPersonas(listaPersonas);

StdOut.println("Despliegue de las personas");


StdOut.println(listaPersonas.toString());
StdOut.println();

}//Fin main

}// Fin ListaPersonasApp


2.66

Se imprime:

Despliegue de las personas Despliegue con método


Martinez Jose 24 estático de la App
Tapia Luis 37 desplegarPersonas
Viorklumds Jorge 43
Ferrada Cecilia 63
Vega Carlos 21
Despliegue
Despliegue de las personas utilizando en
Persona [apellido=Martinez, nombre=Jose, edad=24] StdOut.println
Persona [apellido=Tapia, nombre=Luis, edad=37] el método
Persona [apellido=Viorklumds, nombre=Jorge, edad=43] toString de la
Persona [apellido=Ferrada, nombre=Cecilia, edad=63] clase
Persona [apellido=Vega, nombre=Carlos, edad=21] ListaPersonas

Buscando a Martinez
Encontrado Martinez Jose 24

Eliminando Viorklumds, Vega y Alfaro


si elimino a Viorklumds
si elimino a Vega

Despliegue de las personas


Martinez Jose 24
Tapia Luis 37
Ferrada Cecilia 63

Despliegue de las personas


Persona [apellido=Martinez, nombre=Jose, edad=24]
Persona [apellido=Tapia, nombre=Luis, edad=37]
Persona [apellido=Ferrada, nombre=Cecilia, edad=63]
2.67
Supongamos que en la creación de los objetos Persona se usará la misma
referencia p.

// inserta 4 items
Persona p = new Persona("Martinez", "Jose", 24);
listaPersonas.ingresarPersona(p);
p = new Persona("Tapia","Luis",37);
listaPersonas.ingresarPersona(p);
p = new Persona("Viorklumds", "Jorge", 43);
listaPersonas.ingresarPersona(p);
p = new Persona("Ferrada", "Cecilia", 63);
listaPersonas.ingresarPersona(p);

listaPersonas

Con:
Persona p = new Persona("Martinez", "Jose", 24);
listaPersonas.ingresarPersona(p);

cantidadPersonas
0
1
Persona
apellido: Martinez
nombre: Jose
edad: 24

p = listaPersonas[0]
2.68
Con:
p = new Persona("Tapia","Luis",37);
listaPersonas.ingresarPersona(p);
cantidadPersonas
0
1
2

Persona Persona
apellido: Martinez apellido: Tapia
nombre: Jose nombre: Luis
edad: 24 edad: 37

p ≠ listaPersonas[0] p = listaPersonas[1]

Persona
El objeto apellido: Martinez no es basura, ya que se puede llegar a él a través de
nombre: Jose
edad: 24

listaPersonas[0]
2.69
2.5.2. Ordenamiento de un contenedor de objetos

Persona * ListaPersonas
- String apellido - Persona [] lista
- String nombre - int cantidadPersonas
- int edad + ListaPersonas(int max)
+ insertar(Persona persona): boolean
+ Persona(String apellido,
+ ordenamientoSimple()
String nombre, int edad)
+ getCantidadPersonas(): int
+ get y set …. + getPersona (int i): Persona
+ toString(): String + toString(): String

public class Persona {


private String apellido;
private String nombre;
private int edad;

public Persona(String apellido, String nombre, int edad) {


this.apellido = apellido;
this.nombre = nombre;
this.edad = edad
}

public String getApellido(){


return apellido;
}

// get y set ….

// toString()….

}//fin clase Persona


2.70
public class ListaPersonas {
private Persona[] lista; //referencia al arreglo
private int cantidadPersonas; //número de ítems
private int max;

public ListaPersonas(int max) { //constructor


lista = new Persona[max]; //crea el arreglo
cantidadPersonas = 0; //no hay items todavía
this.max = max;
}

public boolean insertar(Persona persona){


if (cantidadPersonas < max){
lista[cantidadPersonas] = persona;
cantidadPersonas++; //incrementa el tamaño
return true;
}
else{
return false;
}
}

public int getCantidadPersonas(){


return cantidadPersonas;
}

public Persona getPersona (int i){


if (i >= 0 && i < cantidadPersonas){
return lista[i];
}
return null;
}
2.71
public void ordenamientoSimple(){
for (int i = 0; i < cantidadPersonas; i++){
for(int j = i+1; j<cantidadPersonas; j++) {
if(lista[i]getApellido().compareTo(lista[j].getApellido())>0){
Persona temp = lista[i];
lista[i] = lista[j];
lista[j] = temp;
}
} //fin del for interno
}//Fin del for externo

} //fin ordenamientoSimple

//toString()....

} //fin clase ListaPersonas

public class ListaPersonasApp {

public static void ingresarPersonas(ListaPersonas listaPersonas){


listaPersonas.insertar(new Persona("Martínez", "José", 24));
listaPersonas.insertar(new Persona("Tapia","Luis",37));
listaPersonas.insertar(new Persona("Viorklumds", "Jorge", 43));

Persona persona = new Persona("Galleguillos","Ingrid",72);


listaPersonas.insertar(persona);
Persona persona1 = new Persona("Alfaro","Eduardo",54);
listaPersonas.insertar(persona1);
Persona persona2 = new Persona("Sanchez", "Yazmin", 22);
listaPersonas.insertar(persona2);
}
2.72
public static void main(String[] args){
int max = 100; //tamaño del contenedor
ListaPersonas listaPersonas; //referencia al contenedor
//Crea el contenedor
listaPersonas = new ListaPersonas(max) ;

ingresarPersonas(listaPersonas);

StdOut.println(“Antes de ordenar:”) ;
desplegarPersonas(listaPersonas); Se podría desplegar la
lista de personas usando
listaPersonas.ordenamientoSimple(); el método toString(),
como en el caso del
StdOut.println(“Despues de ordenar:”) ; ejemplo anterior
desplegarPersonas(listaPersonas);

}//fin main()

public static void desplegarPersonas (ListaPersonas listaPersonas){


//Despliega las personas
for(int i = 0; i < listaPersonas.getCantidadPersonas(); i++){
Persona persona = listaPersonas.getPersonaI(i);
StdOut.println(persona.getApellido());
//StdOut.println(persona.toString());
}
}

}//fin clase ListaPersonasApp


2.73
2.6. Navegabilidad

2.6.1 Concepto de navegabilidad

Ejercicio
Un médico tiene rut, nombre, registro médico y especialidad. Un paciente
tiene rut, nombre, diagnóstico y médico de cabecera (sólo 1).

La aplicación debe realizar lo siguiente:


a) Ingresar un médico
b) Ingresar un paciente (sólo rut y nombre)
c) Ingresar el diagnóstico de un paciente
d) Asignar un médico a un paciente

Para este problema, se deben tener 2 objetos, uno de la clase Paciente y otro
de la clase Medico. Es necesario poder llegar desde el paciente a su médico
para poder realizar el requerimiento (d). Esto significa que se necesita poder
navegar desde paciente a médico.

Entonces,
 Se pueden agregar flechas en los relacionamientos para indicar
navegabilidad.
1
Orden* Cliente
Compra

 A partir de la orden de compra, se puede conocer el cliente asociado.


 A partir de un cliente no se puede conocer las ordenes de compra que
tiene asociadas.

 La responsabilidad no es simétrica, existe sólo resposabilidad a un lado de


la línea.
2.74
2.6.2. Implementación de asociaciones 1:1

1 1
A B

Ejemplo: Asociación entre Universidad y Rector.

A B

Ref. B. Ref. A.

Retomando el ejercicio
Un médico tiene rut, nombre, registro médico y especialidad. Un paciente
tiene rut, nombre, diagnóstico y médico de cabecera (sólo 1).

La aplicación debe realizar lo siguiente:


a) Ingresar un médico
b) Ingresar un paciente (sólo rut y nombre)
c) Ingresar el diagnóstico de un paciente
d) Asignar un médico a un paciente

Se pide: Modelo del dominio, diagrama de clases del dominio de la


aplicación y código
2.75
Modelo del dominio

1 *
Médico Paciente
atiende
Rut Rut
Nombre Nombre
Registro médico Diagnóstico
especialidad

Diagrama de Clases del dominio de la aplicación

Medico Paciente
1 *
- String rut - String rut
- String nombre - String nombre
- String registroMedico - String disgnostico
- String especialidad - Medico medico
+ Paciente ()
+ Medico() + setDiagnostico(String diagnostico)
+ get y set …. + getMedico(): Medico
+ toString(): String + setMedico(Medico medico)
+ toString(): String
2.76
Refino de la solución
main( ) {
Crear el objeto médico
Crear el objeto paciente
Ingresar diagnóstico del objeto paciente
Asociar el objeto médico al objeto paciente
}

public class Medico {


private String rut;
private String nombre;
private String registroMedico;
private String especialidad;

public Medico(String rut, String nombre, String registro, String especialidad){


this.rut = rut;
this.nombre = nombre;
this.registroMedico= registro;
this.especialidad = especialidad;
}

//get y set ….

//toString()…

} //Fin clase Medico


2.77
public class Paciente {
private String rut;
private String nombre;
private String diagnostico;
private Medico medico;

public Paciente (String rut, String nombre){


this.rut =rut;
this.nombre = nombre;
this.medico = null;
this.diagnostico = null;
}

public void setDiagnostico(String diagnostico){


this.diagnostico = diagnostico;
}

public void setMedico(Medico medico){ //asocia al medico


this.medico = medico;
}

public Medico getMedico (){


return this.medico;
}

//get y set …..

//toString() ….

} //Fin clase Paciente


2.78
public class App {
public static void main (String [ ] args) {
Medico m1 = new Medico(“111-k”, “Juan Perez”,
“151-5”, “cardiologo”);
Paciente p1 = new Paciente(“222-1”, “Pedro Soto”);
p1.setDiagnostico(“Apendicitis”);
p1.setMedico(m1);
}
}

Diagrama de Objetos

m1: Medico p1: Paciente

rut=111-k rut=222-1

nombre=Juan Perez nombre=Pedro Soto

registroMedico=151-5 diagnostico=Apendicitis

especialidad=cardiologo medico
2.79
2.6.3. Implementación de una asociación 1:N y/o N:N

Ejercicio
Se necesita manejar información de un país y sus ciudades. Para un país
interesa saber su nombre, idioma y cantidad de habitantes. Para una ciudad,
su nombre, alcalde (suponga que sólo 1 alcalde por ciudad) y cantidad de
habitantes. Se pide que haga un programa en Java que:
a. Ingrese el país Chile. Suponga que tiene 18.000.000 de habitantes.
b. Ingrese N ciudades de Chile, donde N se lee desde pantalla (lea desde
pantalla los datos de cada ciudad)
c. Una vez ingresada la información del país y sus ciudades, despliegue el
nombre del país y el nombre de cada una de sus ciudades.

Para este problema, se debe crear un objeto país y varios objetos de la clase
Ciudad. Es necesario poder llegar desde el país a sus ciudades para poder
realizar el requerimiento (c). Esto significa que se necesita poder navegar
desde paciente a sus ciudades

Asociación 1: N
1 1..n
A B

Ejemplo: Asociación entre Departamento y Profesor.

A B

Conjunto Ref. A.
de ref.
2.80
Asociación N: N
1..n 1..n
A B

Ejemplo: Asociación entre Producto y Cliente.

A B

Conjunto Conjunto
Ref. B. Ref. A.

Para implementar estas asociaciones se usan los contenedores.

Retomando el ejercicio
Se necesita manejar información de un país y sus ciudades. Para un país
interesa saber su nombre, idioma y cantidad de habitantes. Para una ciudad,
su nombre, alcalde (suponga que sólo 1 alcalde por ciudad) y cantidad de
habitantes. Se pide que haga un programa en Java que:
a. Ingrese el país Chile. Suponga que tiene 18.000.000 de habitantes.
b. Ingrese N ciudades de Chile, donde N se lee desde pantalla (lea desde
pantalla los datos de cada ciudad)
c. Una vez ingresada la información del país y sus ciudades, despliegue el
nombre del país y el nombre de cada una de sus ciudades.
Se pide:
 Modelo del dominio
 Diagrama de clases del dominio de la aplicación
 Código
2.81
Modelo del dominio
1 1..*
País Ciudad
Nombre tiene Nombre
Idioma Alcalde
Cantidad de habitantes Cantidad de habitantes

Se debe navegar de país a sus ciudades

Diagrama de Clases del dominio de la aplicación


Ciudad
Pais 1 1 .. *
- String nombre
El contenedor - String nombre
- String idioma
necesario para - String alcalde
- int cantidadHabitantes
la - int cantidadHabitantes
- Ciudad [ ] listaCiudades
- int cantidadCiudades implementación
de la + Ciudad(String nombre,
navegabilidad String alcalde,
+ Pais( String nombre, String idioma, int cantidadHabitantes)
se insertó en la
int cantidadHabitantes, int max) + get y set….
+ get y set …. clase Pais
+ toString(): String
+ getCantidadCiudades(): int
+ getCiudad (int i): Ciudad Métodos
+ ingresarCiudad(Ciudad ciudad): boolean
+ toString(): String asociados al
contenedor
2.82
Refino de la solución
main( ) {
Crear el objeto país (p)
Leer N
for i = 1 to N
Crear el objeto ciudad (c)
Asociar el objeto ciudad al objeto país (de país a ciudad)
end for
“Desplegar el nombre del país y el nombre de sus ciudades”
}

“Desplegar el nombre del país y sus ciudades”


desplegar nombre del país
Obtener la cantidad de ciudades del país (N)
Para cada ciudad (for I = 0 to N – 1):
Obtener la ciudad
obtener su nombre
desplegar el nombre

public class Ciudad {


private String nombre;
private String alcalde;
private int cantidadHabitantes;

public Ciudad (String nombre, String alcalde, int cantidadHabitantes) {


this.nombre = nombre;
this.alcalde= alcalde;
this.cantidadHabitantes = cantidadHabitantes;
}
public String getNombre ( ) {
return nombre;
}
//get y set …..
//toString()…
}
2.83
public class Pais {
private String nombre;
private String idioma;
private int cantidadHabitantes;
private Ciudad [ ] listaCiudades;
private int cantidadCiudades;
private int max

public Pais (String nombre, String, idioma, int cantidadHabitantes,


int max) {
this.nombre = nombre;
this.idioma= idioma;
this.cantidadHabitantes = cantidadHabitantes;
this.listaCiudades = new Ciudad[max];
this.cantidadCiudades = 0;
this.max = max;
}

public boolean ingresarCiudad (Ciudad ciudad) {


if (cantidadCiudades < max) {
listaCiudades [cantCiudades] = ciudad;
cantidadCiudades ++;
return true;
}
return false;
}

public String getNombre ( ) {


return nombre;
}

public int getCantidadCiudades( ) {


return cantidadCiudades;
}
2.84
public Ciudad getCiudad (int i ) {
if (i >= 0 && i < cantidadCiudades){
return listaCiudades[i];
}
else{
return null;
}
}
//toString()
}//Fin clase Pais
Debieran haber subprogramas
(métodos estáticos de la App) para
le lectura y despliegue de los
datos
public class App {

public static void main(String [ ] args) {


StdOut.print(“Ingrese cantidad de ciudades de Chile”);
int cantidadCiudades = StdIn.readInt();

Pais pais = new Pais (“Chile”, “Español”,


18000000, cantidadCiudades);

for (int I = 1; I <= cantidadCiudades; I++) {


StdOut.print(“Ingrese nombre ciudad”);
String nombre = StdIn.readString();
StdOut.print(“Ingrese Alcalde”);
String alcalde = StdIn.readString();
StdOut.print(“Ingrese cantidad de habitantes”);
int cantidadHabitantes = StdIn.readInt();
Ciudad ciudad = new Ciudad(nombre, alcalde, cantidadHabitantes);
pais.ingresarCiudad(ciudad);
}
2.85
// Desplegar datos en pantalla del país y sus ciudades
System.out.println(pais.getNombre ( ));
cantidadCiudades = pais.getCantidadCiudades();
for (i = 0; i < cantidadCiudades ; i++) {
Ciudad ciudad = pais.getCiudadI(i);
StdOut.println(ciudad.getNombreC( );
}
}
}
Se podría desplegar la información del pais
y sus ciudades, mediante el método to String()

Diagrama de Objetos
c: Ciudad

nombre= Santiago
alcalde= Alessandri
cantidadHabiatntes= 6000000

p: Pais
c: Ciudad
nombre= Chile
nombre= Antofagasta
idioma=Español
cantidadHabitanes=18000000 alcalde= Rojo
cantidadHabitantes= 400000

listaCiudades

cantidadCiudades= 3 c: Ciudad

nombre= Concepcion
alcalde= Ortiz
cantidadHabitantes= 1000000
2.86
Otra solución del mismo problema
Diagrama de Clases del dominio de la aplicación

Pais Ciudad
- String nombre - String nombre
- String idioma - String alcalde
- int cantidadHabitantes - int cantidadHabitantes
- ListaCiudades listaCiudades + Ciudad(String nombre,
String alcalde,
+ Pais( String nombre, String idioma, int cantidadHabitantes)
int cantidadHabitantes, int max) + get y set()…
+ get y set()…. + toString(): String
+ getListaCiudades(): ListaCiudades
+ toString(): String *
1
ListaCiudades
- Ciudad [] lc
- int cantidadCiudades
- int max
+ ListaCiudades(int max )
+ getCantidadCiudades(): int
+ insertarCiudad(Ciudad ciudad):
boolean
+ getCiudad (int i): Ciudad
+ toString(): String

Esta solución tiene la ventaja que si cambiamos la forma de implementar la


lista, el código de la clase País no cambia. Ea solución anterior, habría que
intervenir en este código para hacer los cambios
2.87
public class Pais {
private String nombre; Objeto contenedor
private String idioma;
private int cantidadHabitantes;
private ListaCiudades listaCiudades;
public Pais (String nombre, String idioma, int cantidadHabitantes,
int max) {
this.nombre = nombre;
this.idioma= idioma;
this.cantidadHabitantes = cantidadHabitantes;
this.listaCiudades = new ListaCiudades(max);
}
public int getCantidadHabitantes() {
return this.cantidadHabitantes;
}

public String getIdioma() {


return this.idioma;
}
public String getNombre () {
return this.nombre;
}
La responsabilidad
public boolean ingresarCiudad(Ciudad ciudad){ de ingresar una
return listaCiudades.insertarCiudad(ciudad); ciudad a un país es
del país
}

public ListaCiudades getListaCiudades() {


return this.listaCiudades;
}
//toString()…..
}
2.88
public class Ciudad {
private String nombre;
private String alcalde;
private int cantidadHabitantes;

public Ciudad (String nombre, String alcalde, int cantidadHabitantes){


this.nombre = nombre;
this.alcalde= alcalde;
this.cantidadHabitantes = cantidadHabitantes;
}
public String getAlcalde() {
return this.alcalde;
}
public int getCantidadHabitantes() {
return this.cantidadHabitantes;
}
public String getNombre () {
return this.nombre;
}
//toString()….
}
2.89
public class ListaCiudades {
private Ciudad [] lc;
private int cantidadCiudades;
private int max;
public ListaCiudades (int max) {
lc = new Ciudad [max];
cantidadCiudades = 0;
this.max = max;
}
public int getCantidadCiudades() {
return cantCiudades;
}
public Ciudad getCiudad (int i) {
if (i>= 0 && i < cantidadCiudades){
return lc[i];
}
else{
return null;
}
}
public boolean insertarCiudad(Ciudad ciudad) {
if (cantidadCiudades < max){
lc[cantidadCiudades] = ciudad;
cantidadCiudades ++;
return true ;
}
else{
return false ;
}
}
//toString()…
}
2.90
public class App {
public static Pais ingresarPaisCiudades(){
StdOut.print ("Ingrese cantidad de ciudades de Chile");
int cantidadCiudades = StdIn.readInt();
Pais pais = new Pais ("Chile", "Español", 18000000, cantidadCiudades);
for (int I = 1; I <= cantidadCiudades; I++) {
StdOut.print("Ingrese nombre ciudad");
String nom = StdIn.readString();
StdOut.print("Ingrese Alcalde");
String alcalde = StdIn.readString();
StdOut.print("Ingrese cantidad de habitantes");
int cant = StdIn.readInt();

Ciudad ciudad = new Ciudad(nom, alcalde, cant);


pais.ingresarCiudad(ciudad);
// Si no se tuviera el método ingresarCiudad en la clase Pais,
//se haría:
// pais.getListaCiudades().insertarCiudad(ciudad);
}
return pais;
}
public static void desplegarPaisCiudades(Pais pais){
StdOut.println(pais.getNombre ( ));
cantidadCiudades = pais.getListaCiudades().getCantidadCiudades();
for (int i = 0; i < cantidadCiudades ; i++) {
Ciudad ciudad = pais.getListaCiudades().getCiudad(i);
StdOut.println(ciudad.getNombre ( ));
}
//Se podría tener
//StdOut.println(pais.getListaCiudades()).toString());
}
public static void main(String[] args) {
Pais pais = ingresarPaisCiudades();
desplegarPaisCiudades(pais)
}//Fin main
} //Fin App
2.91
Modelo del dominio y diagrama de clases del dominio de la aplicación
asociado
Dado el modelo del dominio visto anteriormente, se muestra el diagrama de clases
asociado

1..* inscribe 1..*


Estudiante Asignatura

nombre codigo
rut nombre
Inscripcion creditos

oportunidad

Otra forma

Estudiante Asignatura
tiene tiene
1 1
Rut Código
Nombre Nombre
Créditos
1..* 1..*

Inscripcion

Oportunidad
ListaEstudiantes
- int cantidadEstudiantes 2.92
- Estudiante [] lista
Diagrama de clases - int max
+ ListaEstudiantes(int max)
+ ingresar(Estudiante estudiante):
boolean
+ buscar(String rut): Estudiante
+ eliminar(String rut): boolean
+ getEstudianteI(int i): Estudiante
+ getCantidadEstudiantes(): int
+ setCantidadEstudiantes (
int cantidadEstudiantes)
+ getMax(): int

1 *
ListaInscripciones * Estudiante
Inscripcion 1 - String rut
- int cantidadInscripciones - int oportunidad
- Inscripcion [] lista - String nombre
- Asignatura asignatura - ListaInscripciones listaInscripciones
- int max - Estudiante estudiante
+ ListaInscripciones(int max) Los + Estudiante(String rut, String nombre)
+ Inscripcion(int oportunidad) + getRut(): String
+ ingresar(Inscripcion inscripcion): parámetros
+ getOportunidad(): int + setRut(String rut)
boolean dependerán
+setOportunidad(int oportunidad) + getNombre(): String
+ buscar(): Inscripcion del criterio
+ getEstudiante(): Estudiante + setNombre (String nombre)
+ eliminar(): boolean por el que se
+setEstudiante(Estudiante estudiante)
+ getInscripcionI(int i): Inscripcion quiera buscar + getListaInscripciones(): ListaInscripciones
+ getAsignatura(): Asignatura + setListaInscripciones(ListaInscripciones
+ getCantidadInscripciones(): int y eliminar
+ setAsignatura(Asignatura listaInscripciones)
+ setCantidadInscriciones(
asignatura)
int cantidadInscripciones)
+ getMax(): int 1
+ setMax(int max) 1
Asignatura
ListaAsignaturas - String codigo
- int cantidadAsignaturas - String nombre
* - int creditos
- Asignatura [] lista
- int max - ListaInscripciones listaInscripciones
+ ListaAsignaturas(int max) + Asignatura(String código, String nombre,
+ ingresar(Asignatura asignatura): boolean int creditos)
+ buscar(String codigo): Asignatura + getCodigo(): String
+ setCodigo(String codigo)
+ eliminar(String codigo): boolean
Se podrían tener el + getNombre(): String
+ getAsignaturaI(int i): Asignatura + setNombre (String nombre)
+ getCantidadAsignaturas(): int método toString() en + getCreditos(): int
+ setCantidadAsignaturas ( + setCreditos(int creditos)
int cantidadAsignaturas) cada una de las clases + getListaInscripciones(): ListaInscripciones
+ getMax(): int + setListaInscripciones(
+ setMax(int max) ListaInscripciones listaInscripciones)
2.93
2.7. Interfaces
Problema
Imaginemos que vamos a crear un programa para conducir unos vehículos con ruedas.
En particular, la persona dueña de estos vehículos usa uno diferente para ir a trabajar
dependiendo del día de la semana.

Una de las primeras cosas que podemos concluir, a partir de nuestro conocimiento de
cómo operan diferentes vehículos, es que en todos los casos, podemos avanzar y
frenar, además de girar a la izquierda y derecha. Independiente de cómo realizan la
acción, esto corresponde a la forma en que los humanos interactúan con la máquina. El
detalle interno de cómo un vehículo particular realiza la acción no debería
preocuparnos (por lo menos, hasta más adelante): tal vez un vehículo acelera usando
un carburador, otro puede ser 100% electrónico, o incluso podría ser a vapor (lo que
implicaría echarle carbón a la caldera y abrir válvulas para dejar pasar el vapor).

Es decir, cualquiera sea el vehículo tiene que avanzar, frenar, girar a la izquierda y
girar a la derecha.

Se pueden tener distintas formas de implementación del avanzar, frenar, girar


izquierda y girar derecha del vehículo, por lo tanto tendremos distintas clases que
implementarán dichos métodos, dependiendo si es un vehículo a vapor o eléctrico, etc

Concepto de interfaz
 Java admite un concepto similar a la clase, llamado interfaz.
 Una interfaz es una colección de métodos abstractos. Un método abstracto no tiene
código.
 Una interfaz puede ser pública o privada.
 Todos los métodos dentro de la interfaz son públicos y abstractos (no se encuentran
implementados).
 Las variables de clase en una interfaz, si es que existen, son implícitamente finales,
públicas y estáticas (en otras palabras, son constantes).
 Una interfaz permite al programador describir un conjunto de capacidades que debe
implementar una clase.
 Una clase que implementa una interfaz, no está heredando nada. Simplemente, se
compromete a implementar los métodos definidos en la interfaz.
 Este es el origen de la palabra clave implements.
2.94
 Polimorfismo en JAVA: Una variable declarada de una cierta interface, puede
mantener valores en cualquier clase, que implementa la interface.

Diagrama de clase
 En un diagrama de clases, el “estereotipo” es una marca que se coloca sobre el
título o sobre una relación para indicar su comportamiento, por ejemplo
<<interface>>.
 En general las clases e interfaces siempre están relacionadas, en este caso, se indica
por una línea segmentada, que indica una relación débil de dependencia

Ejemplo 1

Diagrama de clases
<<interface>>
ListaEstudiantes
+getElemento(int posicion): Estudiante
+buscarElemento(Estudiante elemento): int
+insertarElemento(Estduiante elemento): boolean
+eliminarElemento(int posicion): boolean
+limpiar()
+isVacia():boolean
+getTamanio(): int

<<implements>>

ListaArregloEstatico * Estudiante
- Estudiante [] arreglo - int rut
- int posicionUltimoElemento - String nombre
- String apellido
- String direccion

….
2.95
public class Estudiante {
private int rut;
private String nombre;
private String apellido;
private String direccion;
public Estudiante() {
}
public String getApellido() {
return this.apellido;
}
public void setApellido(String apellido) {
this.apellido = apellido;
}
public String getDireccion() {
return this.direccion;
}
public void setDireccion(String direccion) {
this.direccion = direccion;
}
public String getNombre() {
return this.nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public int getRut() {
return this.rut;
}
public void setRut(int rut) {
this.rut = rut;
}
//toString()….
}//Fin Estudiante
2.96
/**
* Interface que representa el comportamiento de una lista de
* Estudiantes. Esta puede ser implementada de la forma que se desee,
* en este caso a través de un arreglos estáticos (vector)
*
* Se podría querer implementar la lista de estudiantes de otra forma
*/

public interface ListaEstuadiantes {

/**
* Metodo que dada la posicion de un elemento dentro de la lista
* retorna el elemento en esa posicion.
*Si la posicion en la lista no existe retorna null.
* @param posicion
* @return Estudiante/null
*/
public Estudiante getElemento(int posicion);

/**
* Metodo que dado un elemento retorna la posicion en la cual se
* encuentra dentro de la lista. Retorna -1 si el dato no se encuentra.
* @param elemento
* @return int posicion del elemento dentro de la lista.
*/
public int buscarElemento(Estudiante elemento);

/**
* Metodo que inserta un elemento al final de la lista, retorna true si
* fue exitosa la insercion (hay espacio para almacenarlo) o false si
* la lista se encuentra llena.
* @param elemento
* @return boolean true/false
*/
public boolean insertarElemento(Estudiante elemento);
2.97
/**
* Metodo que elimina el elemento en la "posicion" de la lista.
* Si la posición no existe, retorna falso. En caso contrario
* elimina el dato y retorna true.
* @param posicion
* @return boolean true/false
*/
public boolean eliminarElemento(int posicion);

/**
* Metodo que elimina todos los datos de la lista, es decir la
* deja vacia
*/
public void limpiar();

/**
* Metodo que retorna true si y solo si no hay ningún elemento
* presente en la lista
* @return boolean (true/false)
*/
public boolean isVacia();

/**
* Metodo que retorna la cantidad de elementos que posee la lista,
* por ejemplo: Si la lista se encuentra vacia retorna 0;
* @return int cantidad de elementos en la lista.
*/
public int getTamanio();

} //Fin interface ListaAlumnos


2.98
/**
* Clase que implementa la interface Lista que permite almacenar
* Alumnos
*/
public class ListaArregloEstatico implements ListaEstudiantes {
private Estudiante[] arreglo;
private int posicionUltimoElemento;

/**
* Constructor de la clase ListaArregloEstatico
* @param _capacidadMaxima : Cantidad maxima de elementos
* que puede almacenar esta lista.
*/
public ListaArregloEstatico(int capacidadMaxima) {
this.arreglo = new Estudiante[capacidadMaxima];
this.posicionUltimoElemento = -1;
}

public Estudiante getElemento(int posicion) {


if (posicion < 0 || posicion > this.arreglo.length) {
return null;
}
// Si no hay un dato en esa posicion
if (posicion > this.posicionUltimoElemento) {
return null;
}
return this.arreglo[posicion];
}

public int buscarElemento(Estudiante elemento) {


// Recorro el arreglo tratando de encontrar el elemento
for (int i=0; i <= this.posicionUltimoElemento; i++) {
if (this.arreglo[i].getRut()==elemento.getRut()) {
return i;
}
}
// Si no lo encontre, retorno -1
return -1;
}
2.99
public boolean insertarElemento(Estudiante elemento) {
// Si llegue justo a la capacidad maxima no puedo
// almacenar mas.
if (this.posicionUltimoElemento == arreglo.length-1) {
return false;
}
// Incremento el contador de elementos e ingreso el elemento.
this.posicionUltimoElemento++;
this.arreglo[this.posicionUltimoElemento] = elemento;
return true;
}
public void limpiar() {
int tamanio = this.arreglo.length;
this.arreglo = new Estudiante[tamanio];
this.posicionUltimoElemento = -1;
}
public boolean isVacia() {
return (this.posicionUltimoElemento == -1);
}
public int getTamanio() {
return this.posicionUltimoElemento+1;
}
public boolean eliminarElemento(int posicion) {
// Si intento eliminar una posicion que no existe retorno falso
if (posicion < 0 || posicion > this.arreglo.length) {
return false;
}
// Si no hay un dato en esa posicion
if (posicion > this.posicionUltimoElemento) {
return false;
}
// Se procede a realizar el corrimiento para realizar la
// eliminacion
for (int i = posicion; i < this.posicionUltimoElemento; i++) {
this.arreglo[i] = this.arreglo[i+1];
}
this.posicionUltimoElemento--;
return true;
}
} //Fin class ListaArregloEstatico
2.100
public class TestLista {

public static void main(String[] args) {

// Lista que puede almacenar a lo mas 2 objetos.


ListaEstudiantes lista = new ListaArregloEstatico(2);

Estudiante estudiante1 = new Estudiante();


estudiante1.setNombre("Javier");
estudiante1.setApellido("Mandiola");

// inserto al estudiante1 en la lista


if (lista.insertarElemento(estudiante1)) {
StdOut.println("Estudiante 1 insertado con exito");
}
else {
StdOut.println("Estudiante 1 NO insertado");
}

Estudiante estudiante2 = new Estudiante();


estudiante2.setNombre("Claudio");
estudiante2.setApellido("Vasquez");
// inserto al estudiante2 en la lista
if (lista.insertarElemento(estudiante2)) {
StdOut.println("Estudiante 2 insertado con exito");
}
else {
StdOut.println("Estudiante 2 NO insertado");
}

Estudiante estudiante3 = new Estudiante();


estudiante3.setNombre("Paul");
estudiante3.setApellido("Beltrand");
2.101
// inserto al estudiante3 en la lista, pero como la lista
//no tiene espacio esta operacion no es exitosa.
if (lista.insertarElemento(estudiante3)) {
StdOut.println("Estudiante 3 insertado con exito");
}
else {
StdOut.println("Estudiante 3 NO insertado");
}

//Buscar al alumno 2
StdOut.println("Estudiante 2 encontrado en posicion:" +
lista.buscarElemento(estudiante2));

// Eliminacion de elementos en la lista


int k = 0;
if (lista.eliminarElemento(k)) {
StdOut.println("Estudiante en posicion " + k +" eliminado!");
}
else {
StdOut.println("Estudiante en posicion " + k + "No existe!!");
}

} //Fin main

}// Fin class TestLista


2.102
Ejemplo 2 (retomemos el problema)
Imaginemos que vamos a crear un programa para conducir unos vehículos con ruedas. En
particular, la persona dueña de estos vehículos usa uno diferente para ir a trabajar dependiendo del
día de la semana.
Una de las primeras cosas que podemos concluir, a partir de nuestro conocimiento de cómo operan
diferentes vehículos, es que en todos los casos, podemos avanzar y frenar, además de girar a la
izquierda y derecha. Independiente de cómo realizan la acción, esto corresponde a la forma en que
los humanos interactúan con la máquina. El detalle interno de cómo un vehículo particular realiza
la acción no debería preocuparnos (por lo menos, hasta más adelante): tal vez un vehículo acelera
usando un carburador, otro puede ser 100% electrónico, o incluso podría ser a vapor (lo que
implicaría echarle carbón a la caldera y abrir válvulas para dejar pasar el vapor).
Con esto definido, creemos la interfaz pública de todos los vehículos. La llamaremos Vehículo:

interface Vehículo {
void acelerar(); Vehiculo
void frenar(); <<interface>>
acelarar()
void girarDerecha(); frenar()
void girarIzquierda(); girarDerecha()
} girarIzquierda

Además, creemos un main para ejercitar nuestro código:

public class Test1 {


public static void main(String[] args){
Vehículo ve = crearVehículo();

for(int i=0;i<100;i++) {
if (i % 2 == 0) {
ve.acelerar();
} else if (i % 3 == 0) {
ve.frenar();
} else if (i % 5 == 0) {
ve.girarIzquierda();
} else if (i % 7 == 0) {
ve.girarDerecha();
}
}
}

private static Vehículo crearVehículo(){


return null;
}
}
2.103
En este caso, desde el main le pediremos a la función crearVehículo que nos cree un vehículo,
pero por ahora, solo para probar, retornaremos null. En este caso, el código solamente compila: si
lo tratamos de ejecutar fallará. Además, tenemos un ciclo para llamar a los diferentes métodos, de
acuerdo a si el número es divisible por 2, 3, 5, o 7.
Nótese que todo el código se ha escrito sin saber el tipo “real” de objeto que recibiremos (o sea, no
sabemos la clase concreta, si es que es un auto, o carro tirado a caballos, o a vapor, etc).
Simplemente estamos usando las operaciones que nos provee la interfaz. Más adelante podemos
construir clases que implementen el comportamiento concreto de cada tipo, pero mientras
implementen la interfaz especificada, el código seguirá funcionando sin problemas.
Ahora, veamos la creación de los vehículos. Modificaremos el método crearVehículo:

private static Vehículo crearVehículo(){


// Vamos a obtener el día de la semana de "hoy"
Calendar date = Calendar.getInstance();
int dayOfTheWeek = date.get(Calendar.DAY_OF_WEEK);

// Dependiendo del día, es el vehículo que usamos:


switch(dayOfTheWeek) {
case Calendar.MONDAY:
case Calendar.THURSDAY:
case Calendar.FRIDAY:
// return new TeslaE3();
break;
default:
// return new Carruaje();
}
return null;
}
Por ahora, los return de las clases concretas están comentados, ya que necesitamos
implementar dichas clases primero. Veamos el caso del carruaje:
Vehiculo
class Carruaje implements Vehículo{ <<interface>>
acelarar()
private Caballo caballo = new Caballo(); frenar()
@Override girarDerecha()
girarIzquierda
public void acelerar() { caballo.acelerar(); }
<<implements>>
@Override
public void frenar() { caballo.frenar(); }
Carruaje
@Override - Caballo caballo
public void girarDerecha(){caballo.indicarDerecha();}
@Override
public void girarIzquierda() { caballo.indicarIzquierda(); }
}
2.104
El carruaje es tirado por un caballo, por lo que las operaciones del vehículo se traducen en
órdenes al caballo. Éste se implementa así:

class Caballo {
public void acelerar() { }
public void frenar() { }
public void indicarDerecha() { }
public void indicarIzquierda() { }
}

En el caso del otro tipo de vehículo, tendremos lo siguiente:

class TeslaE3 implements Vehículo {


private Motor motorIzquierda = new Motor();
private Motor motorDerecha = new Motor();

@Override Vehiculo
public void acelerar(){ <<interface>>
acelarar()
motorIzquierda.acelerar();
frenar()
motorDerecha.acelerar(); girarDerecha()
} girarIzquierda

@Override <<implements>>
public void frenar(){
motorIzquierda.frenar(); TeslaE3
motorDerecha.frenar(); - Motor motorIzquierda
} - Motor motorDerecha

@Override
public void girarDerecha(){
motorIzquierda.acelerar();
motorDerecha.frenar();
}

@Override
public void girarIzquierda(){
motorIzquierda.frenar();
motorDerecha.acelerar();
}
}
2.105
Supondremos que este vehículo tiene tracción delantera, y que tiene un motor conectado a
cada rueda, por lo tanto para cumplir las operaciones de la interfaz, la secuencia de pasos que tiene
que realizar es diferente (respecto al vehículo tirado por un caballo), pero igual cumple cada
operación.
Desde el punto de vista del “usuario” de la interfaz, no hay diferencia entre ambos tipos de
vehículos: ambos operan de la misma forma. Ahora podemos descomentar las líneas para crear las
clases específicas de vehículos:

private static Vehículo crearVehículo(){


// Vamos a obtener el dia de la semana de "hoy"
Calendar date = Calendar.getInstance();
int dayOfTheWeek = date.get(Calendar.DAY_OF_WEEK);

// Dependiendo del dia, es el vehículo que usamos:


switch(dayOfTheWeek) {
case Calendar.MONDAY:
case Calendar.THURSDAY:
case Calendar.FRIDAY:
return new TeslaE3();
default:
return new Carruaje();
}
}

Como ejercicio, se pueden completar las operaciones de las clases Motor y Caballo para que
escriban por pantalla mensajes apropiados cada vez que sus métodos son llamados.
2.106
Ejemplo 3
Como se dijo anteriormente, las interfaces permiten definir el contrato que una clase debe cumplir.
Esta es una cualidad que puede ser usada de diferentes maneras, y en particular lo
ejemplificaremos usando algo que el mismo Java trae.

En Java se pueden crear interfaces gráficas de usuario (GUI en inglés). En otras palabras, se
pueden crear ventanas, botones y todo lo que se necesita para crear aplicaciones visuales.
Por ejemplo, este código:

import javax.swing.JFrame;

public class Test{


public static void main(String[] args){
JFrame frame = new JFrame("Ejemplo");

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setSize(400, 300);

frame.setVisible(true);
}
}

Al ejecutarlo, genera la siguiente ventana:

Ahora, ¿qué tiene que ver esto con las interfaces? La respuesta se relaciona con un concepto que se
llama Eventos.

¿Qué es un evento?
Cuando creamos interfaces gráficas, siempre necesitaremos responder a las acciones que el usuario
hace en la pantalla. Por ejemplo, presionar un botón. Si el usuario presiona un botón, significa que
2.107
se va a generar el evento “presionar el botón” y de alguna forma tenemos que escribir código
que responda a dicho evento y haga lo que tenga que hacer.

En el caso de Java, al usar las clases de Swing (son las clases que contienen la funcionalidad para
crear componentes gráficos), el sistema de manejo de eventos se diseñó basándose en interfaces.

Hay otros lenguajes en que esto se implementa de otras maneras, pero en el caso de Java, sus
diseñadores decidieron que se implementaría así.

En términos prácticos, en Swing, cuando se desea responder a cierto tipo de eventos, se le debe
indicar al componente (por ejemplo, un botón) que queremos realizar acciones cuando el evento
suceda. Eso se realiza invocando un método en el componente y pasándole como parámetro una
instancia de una clase que “recibirá” los eventos y nos permitirá reaccionar a ellos. A esto muchas
veces se le denomina “registrar un escuchador”.

Por ejemplo, en el código anterior, vamos a reaccionar al evento “click” de la ventana misma, de
forma de escribir algo en la consola cada vez que el usuario hace click con su mouse. Para esto, le
indicamos al componente (en este caso, la ventana) que estamos interesados en los eventos del
mouse, y le pasamos una instancia de una clase:

JFrame frame = new JFrame("Ejemplo");

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.getContentPane().addMouseListener(.........);

frame.setSize(400, 300);

frame.setVisible(true);

En este caso, en la línea 3 le estamos diciendo a la ventana que estamos interesados en responder a
los eventos producidos por el mouse (o sea, registrar un escuchador). En este caso, no se ha
especificado nada y se requiere reemplazar “……..” por una instancia que recibirá los eventos.
En este caso concreto, Swing define el método addMouseListener de esta forma:

public void addMouseListener(MouseListener l) {


// Acá va el código (no nos interesa actualmente)
}

Como se puede ver, Swing requiere que la instancia que reciba los eventos DEBE implementar la
interfaz especificada. Los diseñadores especificaron que esta interfaz tenga las siguientes
operaciones:
2.108
public interface MouseListener {
/**
* Invoked when the mouse button has been clicked (pressed
* and released) on a component.
* @param e the event to be processed
*/
public void mouseClicked(MouseEvent e);

/**
* Invoked when a mouse button has been pressed on a component.
* @param e the event to be processed
*/
public void mousePressed(MouseEvent e);

/**
* Invoked when a mouse button has been released on a component.
* @param e the event to be processed
*/
public void mouseReleased(MouseEvent e); MouseListener
<<interface>>

/**
* Invoked when the mouse enters a component. + mouseClicked(MouseEvent e)
* @param e the event to be processed + mousePressed(MouseEvent e)
*/ + mouseReleased(MouseEvent e)
+ mouseEntered(MouseEvent e)
public void mouseEntered(MouseEvent e); + mouseExited(MouseEvent e)

/**
* Invoked when the mouse exits a component.
* @param e the event to be processed
*/
public void mouseExited(MouseEvent e);
}

De esta forma, los componentes sabrán qué métodos invocar cuando se produzcan los diferentes
eventos del mouse.
Desde el punto de vista nuestro, fácilmente podemos implementar las clases que recibirán los
eventos. Concretamente, en nuestro ejemplo, solo tenemos que crear una clase que implemente la
interfaz anterior:
2.109
class EventosDelMouse implements MouseListener{
@Override
public void mouseClicked(MouseEvent e){
System.out.println("Alguien hizo click!");
}
MouseListener
<<interface>>
@Override
public void mousePressed(MouseEvent e){
} + mouseClicked(MouseEvent e)
+ mousePressed(MouseEvent e)
+ mouseReleased(MouseEvent e)
@Override + mouseEntered(MouseEvent e)
public void mouseReleased(MouseEvent e){ + mouseExited(MouseEvent e)
}

@Override <<implements>>
public void mouseEntered(MouseEvent e){
} EventosDelMouse

@Override
public void mouseExited(MouseEvent e){
}
}

public class Test{


public static void main(String[] args){
JFrame frame = new JFrame("Ejemplo");

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

EventosDelMouse escuchador = new EventosDelMouse(); // <--


frame.getContentPane().addMouseListener(escuchador); // <--

frame.setSize(400, 300);

frame.setVisible(true);
}
}

Como se puede ver, se ha definido una clase que implementa la interfaz. Esto significa que
TODAS las operaciones deben estar en la clase concreta. Después, se usa addMouseListener
para indicar que la instancia “escuchador” será la que responderá a los eventos del mouse de la
ventana.
2.110

Cuando el usuario haga “click” en la ventana, Swing llamará automáticamente el método


mouseClicked de la instancia, ejecutándose todo el código ahí presente (en este caso, solamente
un print).

En este ejemplo en particular, uno se puede preguntar qué pasa con el resto de los eventos. En
teoría, se puede reaccionar a otros eventos diferentes del “click” (botón presionado, botón liberado,
etc). De acuerdo a cómo está el código, Swing llamará a los métodos correspondientes cuando los
eventos suceden, pero no hay código en esos métodos, así que no sucederá nada.

Nótese que aun cuando no necesitemos reaccionar a otros eventos, la instancia que pasemos a
addMouseListener debe implementar todas las operaciones de la interfaz MouseListener . Si
no es así, entonces el código no compilará ya que técnicamente la clase no implementa
correctamente la interfaz:

class EventosDelMouse implements MouseListener{


@Override
public void mouseClicked(MouseEvent e){
System.out.println("Alguien hizo click!");
}
}

En este caso, esta clase no implementa correctamente la interfaz.


En Swing se pueden definir otros eventos, por ejemplo, podemos detectar cuando el mouse se
mueve sobre un componente. Estos eventos se recogen usando otro tipo de interfaz:

JFrame frame = new JFrame("Ejemplo");

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

EventosDelMouse escuchador = new EventosDelMouse(); // <--


frame.getContentPane().addMouseListener(escuchador); // <--

frame.getContentPane().addMouseMotionListener(escuchadorMotion);
// <--

frame.setSize(400, 300);

frame.setVisible(true);

En este caso, llamando a addMouseMotionListener especificamos una instancia que recibirá


los eventos de movimiento. La interfaz que se debe implementar es:
2.111
public interface MouseMotionListener {

/**
* Invoked when a mouse button is pressed on a component and then
* dragged. {@code MOUSE_DRAGGED} events will continue to be
* delivered to the component where the drag originated until the
* mouse button is released (regardless of whether the mouse position
* is within the bounds of the component).
* <p>
* Due to platform-dependent Drag&amp;Drop implementations,
* {@code MOUSE_DRAGGED} events may not be delivered during a native
* Drag&amp;Drop operation.
* @param e the event to be processed
*/
public void mouseDragged(MouseEvent e);

/**
* Invoked when the mouse cursor has been moved onto a component
* but no buttons have been pushed.
* @param e the event to be processed MouseMotionListener
<<interface>>
*/
public void mouseMoved(MouseEvent e);
+ mouseDragged (MouseEvent e)
} + mouseMoved (MouseEvent e)

Para completar el ejemplo, se requiere instanciar un objeto


que implemente dicha interfaz:

class EventosMotion implements MouseMotionListener{ <<implements>>


@Override
public void mouseDragged(MouseEvent e){ EventosMotion

}
@Override
public void mouseMoved(MouseEvent e){
System.out.println("Mouse movido!");
}
}

class EventosDelMouse implements MouseListener { … }


2.112
public class Test{
public static void main(String[] args){
JFrame frame = new JFrame("Ejemplo");

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

EventosDelMouse escuchador = new EventosDelMouse();

frame.getContentPane().addMouseListener(escuchador);

EventosMotion escuchadorMotion = new EventosMotion();

frame.getContentPane().addMouseMotionListener(escuchadorMotion);

frame.setSize(400, 300);

frame.setVisible(true);
}
}

En este caso, se han declarado dos clases diferentes, y de cada una se creó una instancia que
recibirá los mensajes desde Swing. Esto es totalmente válido y funciona.

Muchas veces, al crear clases que implementan interfaces, conviene recordar que una clase puede
realmente implementar varias interfaces en forma simultánea. Podemos refactorizar nuestro
ejemplo para demostrar esto:

class EventosDelMouse implements MouseListener, MouseMotionListener{


@Override
public void mouseClicked(MouseEvent e){
System.out.println("Alguien hizo click!");
}

@Override
public void mousePressed(MouseEvent e) {}

@Override
public void mouseReleased(MouseEvent e) {}

@Override
public void mouseEntered(MouseEvent e) {}
2.113
@Override
public void mouseExited(MouseEvent e) {}

@Override
public void mouseDragged(MouseEvent e) {}

@Override
public void mouseMoved(MouseEvent e){
System.out.println("Mouse movido!");
}
}

MouseListener
<<interface>>

MouseMotionListener + mouseClicked(MouseEvent e)
<<interface>> + mousePressed(MouseEvent e)
+ mouseReleased(MouseEvent e)
+ mouseDragged (MouseEvent e) + mouseEntered(MouseEvent e)
+ mouseMoved (MouseEvent e) + mouseExited(MouseEvent e)

<<implements>>

<<implements>>

EventosDelMouse
2.114
public class Test{
public static void main(String[] args) {
JFrame frame = new JFrame("Ejemplo");

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

EventosDelMouse escuchador = new EventosDelMouse();//<--


frame.getContentPane().addMouseListener(escuchador);//<--
frame.getContentPane().addMouseMotionListener(escuchador);//<--

frame.setSize(400, 300);

frame.setVisible(true);
}
}

Desde el punto de vista de Swing, solo le interesa que la instancia que recibe implemente la
interfaz indicada. En este caso, como la clase (y por lo tanto la instancia) implementa ambas
interfaces, no hay problema en usarla como receptora de ambos tipos de eventos (Swing no se
confundirá al llamar a los métodos correspondientes cuando sucedan los eventos).
2.115
2.8. Arquitectura de una aplicación

2.8.1. Contratos

 Luego de realizar el modelo de dominio, el siguiente paso es crear los


contratos.
 Un contrato es una operación atómica del sistema, se hace o no se hace
 El diseño por contrato establece los derechos y responsabilidades para
cada elemento que conforma un sistema.
Los contratos son para el
diseñador y/o programador
de manera de tener claro lo
que hace y no hace la
aplicación

 Un contrato define lo que se desea lograr con una operación


 Describe lo qué sucederá y no cómo.
 Definen los pre, post condiciones y aspectos invariantes del sistema.
 En un contrato no va la visibilidad
 Para cada operación del sistema se redacta un contrato.

Beneficio de los Contratos


 Mejora la documentación, lo que implica mejor calidad
2.116

Estructura de un contrato
Operación Nombre de la operación y parámetros de entrada y salida
Descripción Breve descripción de la operación
Precondiciones Suposiciones relevantes sobre el estado del sistema o de los objeto
o conceptos del modelo de dominio antes de la ejecución de la
operación.
Son las condiciones que tiene que cumplir el sistema, no la lógica
de la aplicación
Si no existe o no se cumple la precondición, el contrato no es válido
(lanzar un error)
Postcondiciones Resultado esperado de la operación y estado de los objetos o
conceptos del dominio después de que se complete la operación.
 Si solo se obtiene información, no hay post condición
 Si se ingresa, actualiza o elimina información, si hay post
condición

Ejemplos de Contratos
Operación float sqrt(float número)
Descripción Calcula la raíz cuadrada de número
Precondiciones El valor del número debe ser mayor o igual a 0.
Postcondiciones El resultado de la operación contemplará un margen de error de a
lo mucho de un 0,1%.
sqr(número) implica que el resultado obtenido será un número
decimal mayor o igual a 0.
2.117

Operación append(Collection c, Object o)


Descripción Agrega el objeto o a la colección c
Precondiciones Las variables c y o deben estar inicializadas, es decir, no deben
ser nulas. (c!=null && o != null)
Postcondiciones Se agrega el objeto o a la colección c.
El tamaño de c incrementa en 1.

Contratos Tutores
Operación Calcular horas()

Descripción Calcula el número de horas que tiene asignadas un


tutor
Precondiciones El tutor debe haber realizado al menos una actividad
de tutela.
Postcondiciones El valor resultante debe ser mayor o igual a 2.

Operación Calcular incentivo(horas)

Descripción Calcula el incentivo que se da al tutor, en función de


las horas asignadas
Precondiciones El mínimo valor de hora es 2.

Postcondiciones El valor resultante debe ser un entero positivo.


2.118
2.8.2. Implementación de contratos mediante interfaces

Ejemplo Calculadora
Se requiere implementar una calculadora con las 4 operaciones básicas.

Diagrama de
la Interfaz
2.119
Contratos en Java y su documentación
Calculadora
<<interface>>
+ sumar(int x, int y): int
+ restar(int x, int y): int
+ multiplicar(int x, int y): int
+ dividir(int x, int y): int
2.120
2.121
2.122
Implementación de los contratos
 La implementación de los contratos, implica escribir una Clase, la cual
debe incluir como mínimo todos los sub-programas (métodos) que la
interface declara.
 Cuando se trabaja con interfaces, se tiene concentrada en ella todas las
operaciones que nos interesa del sistema
 Un contrato se debe implementar en un método de la interface.
2.123

Calculadora
<<interface>>
+ sumar(int x, int y): int
+ restar(int x, int y): int
+ multiplicar(int x, int y): int
+ dividir(int x, int y): int

<<implements>>

CalculadoraImpl

Calculadora
<<interface>>
public class Calculadora2Impl implements Calculadora{ + sumar(int x, int y): int
… + restar(int x, int y): int
} + multiplicar(int x, int y): int
+ dividir(int x, int y): int

<<implements>> <<implements>>

Calculadora2Impl CalculadoraImpl
2.124
Ejercicio
 Dada la siguiente interfaz, realizar los contratos para cada una de las
operaciones.
 Construir una clase que implemente las operaciones de la interfaz.
 Diseñar el diagrama de clases.

<<interface>>
BancoUCN

- $ int MAX_MONTO = 500


+ agregarAlumno(nombre: String, rut:
String, montoInicial: int): boolean

+ cargarMonedero(rut: String, clave: String,


monto: int): boolean

+ realizarCompra(rut: String, clave: String,


monto: int): boolean
2.125
/**
* Conjunto de funcionalidad que debe realizar
* el sistema.
* @author Diego P. Urrutia <[email protected]>
* @version 2014.03.20
*/

public interface BancoUCN {


/**
* Agrega un alumno al sistema con un saldo inicial.
* Restricciones:
* Que no exista el alumno.
*
* @param nombre del alumno.
* @param rut del alumno.
* @param montoInicial del monedero del alumno.
* @return true si fue posible agregar el alumno,
* falso en otro caso.
*/
public boolean agregarAlumno(String nombre,
String rut, String clave, int montoInicial);
2.126
/**
* Agrega un monto al monedero de un alumno.
* Restricciones:
* Que exista el alumno
*
* @param rut del alumno.
* @param monto de ucn a agregar al monedero.
* @return true si fue posible cargar el monedero.
*/
public boolean cargarMonedero(String rut,
String claveint monto);

/**
* Realiza el pago de una compra por parte del alumno
* Restricciones:
* Que el alumno exista.
* La clave debe ser la del alumno.
*
* @param rut del alumno.
* @param clave del alumno.
* @param monto a descontar del monedero del alumno.
* @return true si fue posible realizar la compra.
*/
boolean realizarCompra(String rut, String clave,
int monto);
}
2.127
Implementación de la interfaz

/**
* Clase que implementa el “como” funciona el sistema,
* a partir del “que”
* declarado por los contratos.
* @author Diego P. Urrutia <[email protected]>
* @version 2014.03.20
*/

public class BancoUCNImpl implements BancoUCN {

private ListaAlumnos listaAlumnos;

/**
* @see BancoUCN#agregarAlumno
*/
public boolean agregarAlumno(String nombre,
String rut, String clave, int montoInicial) {
………
2.128
Diagrama de Clases

- $ MAX_MONTO =500

<<implements>>

1 ListaAlumnos * Alumno
- ListaAlumnos listaAlumno …
….

)
2.129
Uso de interfaces y contratos en el curso
Aun cuando normalmente toda clase tiene contratos que especifican las
operaciones de ésta, y las interfaces se pueden aplicar de muchas formas, en
el caso de este curso, será obligatorio cumplir los siguientes lineamientos:
1. Se definirá una clase “sistema”, con las operaciones necesarias para cumplir los
objetivos del problema que se requiere resolver
2. Las operaciones estarán definidas y documentadas en una interfaz
3. Las operaciones también estarán definidas en contratos, especificando pre,
postcondiciones.
4. Debido a lo anterior, la clase que implemente las operaciones tendrá por nombre
xxxxImpl, siendo xxxx el nombre de la interfaz que define las operaciones

Este será el uso general de los contratos e interfaces durante el curso. A


menos que se diga lo contrario, solo se utilizarán en la clase del “sistema”.
2.130
2.8.3. Modularización de la aplicación mediante paquetes

¡Las clases no andan sueltas, se agrupan en paquetes!

Los paquetes contienen en su interior definiciones de una o más clases


lógicamente relacionadas.

Es una forma de modularizar los programas en JAVA.

El paquete es una colección de clases que se encuentran en el mismo


directorio.

Forma general de un archivo fuente de Java:


 Una única sentencia de paquete (opcional).
 Las sentencias de importación deseadas (opcional).
 Una única declaración de clase pública.
 Las clases privadas dentro del paquete que se requieran (opcional).
2.131
Ejemplo archivo ListaCiudades.java
package cl.ucn.ei.pa.paisciudades.logica;

import cl.ucn.ei.pa.paisciudades.dominio.Ciudad;

public class ListaCiudades { En este ejemplo


private Ciudad[] lc; no se requiere
private int cantidadCiudades; una clase privada
private int max;

public ListaCiudades(int max) {


lc = new Ciudad[max];
cantidadCiudades = 0;
this.max = max;
}
public int getCantidadCiudades() {
return cantidadCiudades;
}
public void setCantidadCiudades(int cantidadCiudades) {
this.cantidadCiudades = cantidadCiudades;
}
public boolean insertarCiudad(Ciudad ciudad) {
if (cantidadCiudades < max) {
lc[cantidadCiudades] = ciudad;
cantidadCiudades++;
return true;
} else {
return false;
}
}
public Ciudad getCiudad(int i) {
if (i >= 0 && i < cantidadCiudades) {
return lc[i];
} else {
return null;
}
}

}
2.132
Formato general de la sentencia package es:
package paq1 [.paq 2[.paq 3]];

Un paquete declarado como:


package java.awt.imagen;

se debe almacenar en:


java\ awt\imagen (Windows)
ó
java/ awt /imagen (UNIX)

Si no se especifica ningún paquete, la clase se incorpora al paquete por


omisión, también conocido como el paquete innominado, pues carece de
nombre.

Todas las clases que se encuentran en archivos de un mismo directorio


forman un mismo paquete.

En JAVA, los paquetes son recipientes con clases, que se utilizan para
mantener el espacio de nombres de clase, dividido en compartimentos.

Por ejemplo, un paquete permite que se cree una clase llamada LISTA,
que se puede almacenar en un paquete propio, sin preocuparse por
conflictos con otra clase llamada LISTA, escrita por otra persona.

Los paquetes se almacenan de una manera jerárquica y se importan


explícitamente, en las definiciones de clases nuevas
2.133
Ejemplo de Jerarquía de paquetes

Paquete
por P
omisión

A. java B. java B. java C. java R

D. java

Paquetes:
Paquete por omisión.
Paquete P
Paquete R

 El paquete P contiene las clases P.B y P.C.


 El paquete P.R contiene la clase P.R.D.
 Las clases A y B, se accesan directamente.
2.134
¿Cómo se organiza un proyecto en los paquetes?
.dominio
 Las clases de los
objetos del dominio.
Por ejemplo, Persona,
Alumno, etc.

.logica
 Interface
pais.nombreOrganización.nombreProyecto
 La clase que
implementa la
Todo en minúscula interface
 Contenedores
 App

.utils
Ejemplo:
 Cualquier cosa que
cl.ucn.ei.pa.sistemaPaisesCiudades
no vaya en lógica
ni en dominio

Recuerde que si el código de un paquete referencia al


código que está en otro paquete, se debe hacer el import
correspondiente
2.135
2.8.4. Ejemplos

Ejemplo 1
Se desea manejar la información de una cuenta bancaria de un banco. Una
cuenta tiene un saldo. Se puede depositar y girar sobre la cuenta bancaria.
La aplicación debe hacer un depósito sobre la cuenta y luego un giro sobre la
misma cuenta. Una vez hechas las transacciones sobre la cuenta, se debe
desplegar su saldo.

Modelo del dominio


Cuenta Bancaria
 saldo

Contratos

Operación Girar (cuenta bancaria, monto giro)


Descripción Se gira dinero desde la cuenta

Precondiciones Que exista la cuenta bancaria

Postcondiciones Saldo actualizado de la cuenta

Operación Depositar (cuenta bancaria, monto depósito)


Descripción Se deposita dinero en la cuenta
Precondiciones Que exista la cuenta bancaria

Postcondiciones Saldo actualizado de la cuenta


2.136
Operación Obtener datos cuenta bancaria
Descripción Se obtienen los datos de la cuenta
bancaria
Precondiciones Que exista la cuenta bancaria
Postcondiciones

Diagrama de clases del dominio de la aplicación

CuentaBancaria

- int saldo

+ CuentaBancaria(int saldo)
+ girar(int montoGiro): boolean
+ depositar(int montoDeposito)
+ getSaldo(): int
+ setSaldo(int saldo)
+ toString(): String
2.137
Diagrama de clases

<<interface>>
SistemaCuentaBancaria

+ depositar(int montoDeposito)
+ girar(int montoGiro)
+ obtener DatosCuentaBancaria(): String

<<implements>>

1 CuentaBancaria
SistemaCuentaBancariaImpl
- CuentaBancaria cuentaBancaria - int saldo
+ CuentaBancaria(int saldo)
+ girar(int montoGiro):
boolean
+ depositar(
int montoDeposito)
+ getSaldo(): int
+ setSaldo(int saldo)
+ toString(): String
2.138

package cl.ucn.ei.pa.proyectocuentabancaria.dominio;

public class CuentaBancaria {


private int saldo;

public final int getSaldo() {


return saldo;
}

public final void setSaldo(int saldo){


this.saldo = saldo;
}

public CuentaBancaria(int saldo) {


this.saldo = saldo;
}

public boolean girar(int montoGiro){


if (montoGiro < saldo){
saldo = saldo - montoGiro;
return true; Que la cantidad a depositar
} (montoDeposito) o la cantidad que
else{ se gira (montoGiro) sea mayor que
return false; 0 debe ser chequeado en la App.
}
} Ahí se validan los datos de entrada
public void depositar (int montoDeposito){
saldo = saldo + montoDeposito;

}
@Override
public String toString() {
return "CuentaBancaria [saldo=" + saldo + "]";
}

}//Fin CuentaBancaria
2.139

package cl.ucn.ei.pa.proyectocuentabancaria.logica;

public interface SistemaCuentaBancaria {

/**
* @param montoDeposito: monto a depositar
*
* Descripción Se deposita dinero en la cuenta
* Precondiciones: Que exista la cuenta bancaria
* Postcondiciones: Saldo actualizado de la cuenta
*
*
*/
public boolean depositar (int montoDeposito);

/**
* @param montoGiro: monto a girar
* Descripción Se gira dinero desde la cuenta
* Precondiciones: Que exista la cuenta bancaria
* Postcondiciones: Saldo actualizado de la cuenta
*/
public boolean girar(int montoGiro);

/**
* @return un string con los datos de la cuenta bancaria
* Descripcion: Retorna los datos de la cuenta bnacraia
* Precondiciones: Que exista la cuenta bancaria
* Postcondiciones
*/
public String obtenerDatosCuentaBancaria();
}
2.140

package cl.ucn.ei.pa.proyectocuentabancaria.logica;
import cl.ucn.ei.pa.proyectocuentabancaria.dominio.CuentaBancaria;
public class SistemaCuentaBancariaImpl implements
SistemaCuentaBancaria{
private CuentaBancaria cuentaBancaria; ;
public SistemaCuentaBancariaImpl(int saldoInicial) {
this.cuentaBancaria = new CuentaBancaria(saldoInicial);
}
Cuando se levanta el sistema se crea el objeto cuenta
bancaria, es decir existe la cuenta
public boolean depositar(int montoDeposito){
if (cuentaBancaria==null){
throw new NullPointerException("Cuenta bancaria
no existe para hacer un deposito");
}  Se trabaja con excepciones para implementar
las precondiciones indicadas en los contratos
 Aquí se lanza la excepción
else{
return cuentaBancaria.depositar(montoDeposito);
}
}
public boolean girar(int montoGiro){
if (cuentaBancaria==null){
throw new NullPointerException("Cuenta bancaria
no existe para hacer un giro");
}
else{
return cuentaBancaria.girar(montoGiro);
}
 Se trabaja con excepciones para implementar
}
las precondiciones indicadas en los contratos
 Aquí se lanza la excepción

public String obtenerDatosCuentaBancaria(){


if (cuentaBancaria==null){
throw new NullPointerException ("Cuenta bancaria
no existe");
}
return cuentaBancaria.toString();
}
}//Fin SistemaCuentaBancariaImpl
2.141

 En la App se leen los datos y se despliegan resultados


 La App representa la interfaz para el ingreso y despliegue de los
datos (podría ser una interfaz gráfica)

public class App {

public static void main(String[] args) {

StdOut.print("Ingrese saldo inicial de la cuenta: ");


int saldo =StdIn.readInt();
//Debiera estar la validación de los datos de entrada

SistemaCuentaBancaria sistema =
new SistemaCuentaBancariaImpl(saldo);

try{
StdOut.println("Datos cuenta bancaria " +
sistema.obtenerDatosCuentaBancaria());
}catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}
 Se trabaja con excepciones para implementar
las precondiciones indicadas en los contratos
 Aquí se está capturando la excepción

try {
sistema.depositar(74);

} catch(NullPointerException ex){
StdOut.println(ex.getMessage());
} La cantidad a girar o
try{ depositar debiera
sistema.girar(20); validarse en la App
}catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}
2.142

 Se trabaja con excepciones para implementar las


precondiciones indicadas en los contratos
 Aquí se está capturando la excepción
try{
StdOut.println("Datos cuenta bancaria " +
sistema.obtenerDatosCuentaBancaria());
}catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}

}//Fin main

} //Fin App

Diagrama de objetos
Si se ingresa como saldo inicial el
valor 100 cuentaBancaria: CuentaBancaria
saldo = 100

174

154

Se imprime
Datos cuenta bancaria CuentaBancaria [saldo= 100]
Datos cuenta bancaria CuentaBancaria [saldo= 154]

Nota: En los talleres se debe trabajar con manejo de excepciones


2.143
Ejemplo 2
Un médico tiene rut, nombre, registro médico y especialidad. Un paciente
tiene rut, nombre, diagnóstico y 1 médico de cabecera.
La aplicación debe realizar lo siguiente:
a) Ingresar un médico
b) Ingresar un paciente (sólo rut y nombre)
c) Ingresar el diagnóstico de un paciente
d) Asignar un médico a un paciente
e) Desplegar al médico
f) Desplegar al paciente, incluyendo el nombre de su médico
Modelo del dominio
1 1..*
Médico Paciente
 rut atiende  rut
 nombre  nombre
 registro médico  diagnóstico
 especialidad

Contratos
Operación Ingresar médico (rut, nombre,
regitro médico, especialidad) Nota
Descripción Se ingresa un médico La validación de los
datos de entrada
Precondiciones (cuando se lee) se hace
Postcondiciones Médico ingresado en la App.

Operación Ingresar paciente (rut, nombre)


Descripción Se ingresa un paciente
Precondiciones
Postcondiciones Paciente ingresado
2.144

Operación Asociar diagnóstico al paciente (diagnostico, rut paciente)


Descripción Se le asigna un diagnóstico al paciente
Precondiciones Que exista el paciente
Postcondiciones Diagnóstico asociado al paciente

Operación Asociar médico al paciente (rut paciente, rut medico)


Descripción Se le asigna un médico al paciente
Precondiciones  Que exista el médico
 Que exista el paciente

Postcondiciones Médico asignado al paciente

Operación Obtener datos del paciente y el de su médico (rut paciente)


Descripción Se obtiene los datos del paciente y los de su médico
Precondiciones Que exista el paciente
Postcondiciones

Operación Obtener datos del medico (rut medico)


Descripción Se obtiene los datos del médico
Precondiciones Que exista el médico
Postcondiciones
2.145
Diagrama de clases del dominio de la aplicación
Medico
- String rut
- String nombre
- String registroMedico
- String especialidad
+ Medico()
+ get y set ….
+ toString(): String
1

Paciente
- String rut
- String nombre
- String diagnostico
- Medico medico
+ Paciente ()
+ setDiagnostico()
+ getMedico(): Medico
+ setMedico(Medico medico)
+ get y set....
+ toString(): String
Diagrama de clases <<interface>> 2.146

SistemaMedico
Los métodos de la
interfaz corresponden + ingresarMedico(String rut, String nombre,
a los contratos. String regitroMedico, String especialidad)
Un método por + ingresar Paciente(String rut, String nombre)
contrato + asociarDiagnostico(String diagnostico, String rut)
+ asociarMedico(String rutPaciente, String rutMedico)
+ obtenerDatosMedico(String rutMedico):String
+ obtenerDatosPacienteYSuMedico(String rutPaciente):String

<<implements>>

Medico
- String rut
- String nombre
- String registroMedico
1 - String especialidad
+ Medico()
+ get y set ….
+ toString();
1

SistemaMedicoImpl
Paciente
- Medico medico - String rut
- Paciente paciente 1 - String nombre
- String diagnostico
- Medico medico
+ Paciente ()
+ setDiagnostico()
+ getMedico(): Medico
+ setMedico(Medico medico)
+ get y set...
+ toString(): String
2.147
package cl.ucn.ei.pa.sistemamedico.dominio;
public class Medico {
private String rut;
private String nombre;
private String registroMedico;
private String especialidad;
public Medico(String rut, String nombre,
String registroMedico, String especialidad) {
this.rut = rut;
this.nombre = nombre;
this.registroMedico= registroMedico;
this.especialidad = especialidad;
}
public String getRut() {
return rut;
}
public void setRut(String rut) {
this.rut = rut;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getRegistroMedico() {
return registroMedico;
}
public void setRegistroMedico(String registroMedico) {
this.registroMedico = registroMedico;
}
public String getEspecialidad() {
return especialidad;
}
public void setEspecialidad(String especialidad) {
this.especialidad = especialidad;
}
@Override
public String toString() {
return "Medico [rut=" + rut + ", nombre=" + nombre +
", registroMedico=" + registroMedico + ",
especialidad="+ especialidad + "]";
}
}//Fin clase Medico
2.148
package cl.ucn.ei.pa.sistemamedico.dominio;
public class Paciente {
private String rut;
private String nombre;
private String diagnostico;
private Medico medico;
public Paciente(String rut, String nombre) {
this.rut = rut;
this.nombre = nombre;
this.diagnostico = null;
this.medico = null;
}
public String getRut() {
return rut;
}
public void setRut(String rut) {
this.rut = rut;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getDiagnostico() {
return diagnostico;
}
public void setDiagnostico(String diagnostico) {
this.diagnostico = diagnostico; Esta versión de toString()
} tiene seleccionada la opción
public Medico getMedico() { del eclipse “saltar valores
return medico; nulos”
}
public void setMedico(Medico medico){ Cuando un objeto está
this.medico = medico; asociado con otro, es
} preferible sobrescribir el
@Override toString que se obtiene con el
public String toString() { Eclipse
return "Paciente [" + (rut != null ? "rut=" + rut +
", " : "")+ (nombre != null ? "nombre=" + nombre +
", " : "")+ (diagnostico != null ? "diagnostico=" +
diagnostico + ", " : "")+
(medico != null ? "medico=" + medico : "") + "]";
}
}//Fin Paciente
2.149

package cl.ucn.ei.pa.sistemamedico.logica;
import cl.ucn.ei.pa.sistemamedico.dominio.*;

public interface SistemaMedico {

public void ingresarMedico(String rut, String nombre,


String registroMedico,String especialidad);
public void ingresarPaciente(String rut, String nombre);
public void asociarDiagnostico(String diagnostico, String rut);
public void asociarMedico(String rutPaciente, String rutMedico);

public String obtenerDatosMedico(String rutMedico);


public String obtenerDatosPacienteySuMedico(String rutPaciente);
}

package cl.ucn.ei.pa.sistemamedico.logica;
import cl.ucn.ei.pa.sistemamedico.dominio.*;

public class SistemaMedicoImpl implements SistemaMedico{

private Medico medico;


private Paciente paciente; Cuando se levanta el
sistema no hay ningún
public SistemaMedicoImpl(){ paciente ni tampoco
medico= null;
paciente= null; un médico
}

public void ingresarMedico(String rut, String nombre,


String registroMedico,String especialidad){

Medico medico=new Medico(rut,nombre,registroMedico,


especialidad);
this.medico = medico;
}
2.150

public void ingresarPaciente(String rut, String nombre){


Paciente paciente = new Paciente (rut, nombre);
this.paciente = paciente;
}

public void asociarDiagnostico(String diagnostico, String rut){


if (paciente==null || !paciente.getRut().equals(rut)){
throw new NullPointerException ("Paciente no existe");
}
paciente.setDiagnostico(diagnostico);
}

public void asociarMedico(String rutPaciente, String rutMedico){


if (paciente==null || medico == null ||
!paciente.getRut().equals(rutPaciente) ||
!medico.getRut.equals(rutMedico)){
throw new NullPointerException ("Paciente y/o medico no existe");
}  Se trabaja con excepciones para
paciente.setMedico(medico); implementar las precondiciones
}
indicadas en los contratos
 Aquí se lanza la excepción
public String obtenerDatosMedico(String rutMedico){
if (medico==null || !medico.getRut.equals(rutMedico)){
throw new NullPointerException ("Medico no existe");
}
return medico.toString();
}

public String obtenerDatosPacienteySuMedico(String rutPaciente){


if (paciente==null || !paciente.getRut.equals(rutPaciente)){
throw new NullPointerException ("Paciente no existe");
}
return paciente.toString();
}

}
2.151

package cl.ucn.ei.pa.sistemamedico.logica;

import cl.ucn.ei.pa.sistemamedico.dominio.*;
import cl.ucn.ei.pa.sistemamedico.logica.SistemaMedico;
import cl.ucn.ei.pa.sistemamedico.logica.SistemaMedicoImpl;
import ucn.StdOut;
 En la App se leen los datos (deben
validarse) y se despliegan resultados
 La App representa la interfaz para el
ingreso y despliegue de los datos
public class App { (podría ser una interfaz gráfica)

public static void main(String[] args) {


SistemaMedico sistema = new SistemaMedicoImpl();

String rutmedico= "111-K";


String nombre = "Juan Perez";
String registroMedico = "151-5";
String especialidad ="cardiologo";
//Debiera estar la validación de los datos de entrada

sistema.ingresarMedico(rutMedico,nombre,
registroMedico,especialidad);

String rutPaciente= "222-1";


nombre = "Pedro Soto";
//Debiera estar la validación de los datos de entrada

sistema.ingresarPaciente(rutPaciente, nombre);
try{
sistema.asociarDiagnostico("Apendicitis", rutPaciente);
}catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}
 Los objetos se crean en la clase que
implementa la interfaz
 Se debe trabajar sin objetos en la App,
sino que con los datos primitivos
2.152

try {
sistema.asociarMedico(rutPaciente, rutMedico);
}catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}

try{
String datosMedico = sistema.obtenerDatosMedico(rutMedico);
StdOut.println("Datos del medico: "+ datosMedico);
}catch( NullPointerException ex){
StdOut.println(ex.getMessage());
}

try{
String datosPaciente =
sistema.obtenerDatosPacienteySuMedico(rutPaciente);
StdOut.println("Datos del paciente: " +
datosPaciente);
}catch( NullPointerException ex){
StdOut.println(ex.getMessage());
}

}//Fin main

}//Fin App

 Se trabaja con excepciones para


implementar las precondiciones indicadas
en los contratos

 Aquí se está capturando la excepción


2.153

Diagrama de Objetos

m1: Medico p1: Paciente

rut=111-k rut=222-1

nombre=Juan Perez nombre=Pedro Soto

registroMedico=151-5 diagnostico=Apendicitis

especialidad=cardiologo medico

Reglas
1. La validación de los datos de entrada se hace en la App
2. La lectura de los datos, los despliegues y la generación de archivos se hace en la
App
3. Los objetos se crean en la clase que implementa la interfaz
4. En un contenedor de objetos se ingresan objetos
5. En la App se trabaja con los datos primitivos, no con objetos
6. Se trabaja con excepciones para las precondiciones de los contratos
7. Si existe un requisito de desplegar ciertos datos, se debe tener un contrato que
obtenga esos datos, un String con todo lo requerido.
2.154
Ejemplo 3
Se necesita manejar información de un país y sus ciudades. Para un país
interesa saber su nombre, idioma y cantidad de habitantes. Para una ciudad,
su nombre, alcalde (suponga sólo 1 alcalde por ciudad) y cantidad de
habitantes. Se pide que haga un programa en Java que:
 Ingrese el país Chile. Suponga que tiene 18.000.000 de habitantes.
 Ingrese N ciudades de Chile, donde N se lee desde pantalla (lea desde
pantalla los datos de cada ciudad)
 Una vez ingresada la información del país y sus ciudades, despliegue
todos los datos del país y los datos de cada una de sus ciudades.

Modelo del dominio


Ciudad 0..* 1 Pais
 nombre pertenece
 nombre
 alcalde  idioma
 cantidad de habitantes  cantidad de habitantes

Contratos
Operación Ingresar un país (nombre, idioma, cantidad habitantes pais)
Descripción Se ingresa un país
Precondiciones
Postcondiciones País creado

Operación Ingresar ciudad de un pais (nombre país, nombre ciudad,


alcalde, cantidadHabitantes)
Descripción Se ingresa una ciudad, quedando asociada al país
Precondiciones Que exista el país
Postcondiciones Se crea la ciudad y se asocia con el pais
2.155

Operación Obtener datos del país y sus ciudades (nombre país)


Descripción Se obtienen los datos del país con sus ciudades
Precondiciones Que exista el país
Postcondiciones

Versión 1

Diagrama de Clases del domino de la aplicación


1 *
Pais Ciudad
tiene
- String nombre
- String nombre
- String idioma
- String alcalde
- int cantidadHabitantes
- int cantidadHabitantes
- Ciudad [ ] listaCiudades
- int cantidadCiudades + Ciudad(String nombre,
+ Pais(String nombre, String idioma, String alcalde,
int cantidadHabitantes) int cantidadHabitantes)
+ get y set …. + get y set….
+ getCantidadCiudades(): int
+ getCiudadI(int i): Ciudad + toString():String
+insertarCiudad(Ciudad ciudad):boolean
+ toString(): String
2.156
Diagrama de clases
<<interface>>
SistemaPaisCiudades
SistemaPaisCiudadesImpl
+ ingresarPais (nombre, idioma,
- Pais pais cantidadHabitantes)
+ obtenerDatosPaisCiudades(): String
+ ingresarCiudadDeUnPais(nombre país,
nombre ciudad, alcalde,
cantidadHabitantes)

1
1 0 .. *
Pais Ciudad

- String nombre
- String nombre
- String idioma
- String alcalde
- int cantidadHabitantes
- int cantidadHabitantes
- Ciudad [ ] listaCiudades
- int cantidadCiudades + Ciudad(String nombre,
String alcalde,
+ Pais(String nombre, String idioma,
int cantidadHabitantes)
int cantidadHabitantes)
+ get y set …. + get y set….
+ getCantidadCiudades(): int + toString():String
+ getCiudadI(int i): Ciudad
+insertarCiudad(Ciudad ciudad):boolean
+ toString(): String
2.157

package cl.ucn.ei.pa.paisciudades.dominio;

public class Ciudad {

private String nombre;


private String alcalde;
private int cantidadHabitantes;

public Ciudad(String nombre, String alcalde,


int cantidadHabitantes) {
this.nombre = nombre;
this.alcalde = alcalde;
this.cantidadHabitantes = cantidadHabitantes;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getAlcalde() {
return alcalde;
}
public void setAlcalde(String alcalde) {
this.alcalde = alcalde;
}
public int getCantidadHabitantes() {
return cantidadHabitantes;
}
public void setCantidadHabitantes(
int cantidadHabitantes) {
this.cantidadHabitantes = cantidadHabitantes;
}
2.158

public String toString() {


return "Ciudad [nombre=" + nombre + ", alcalde=" +
alcalde + ", cantidadHabitantes=" +
cantidadHabitantes + "]";
}
}

package cl.ucn.ei.pa.paisciudades.dominio;
public class Pais {
private String nombre;
private String idioma;
private int cantidadHabitantes;
private Ciudad [] listaCiudades;
private int cantidadCiudades;
private int max;
public Pais(String nombre, String idioma,
int cantidadHabitantes, int max) {
this.nombre = nombre;
this.idioma = idioma;
this.cantidadHabitantes = cantidadHabitantes;
listaCiudades = new Ciudad[max];
cantidadCiudades = 0;
this.max = max;
}
public final String getNombre() {
return nombre;
}
public final void setNombre(String nombre) {
this.nombre = nombre;
}
public final String getIdioma() {
return idioma;
}
2.159

public final void setIdioma(String idioma) {


this.idioma = idioma;
}
public final int getCantidadHabitantes() {
return cantidadHabitantes;
}
public final void setCantidadHabitantes(
int cantidadHabitantes) {
this.cantidadHabitantes = cantidadHabitantes;
}
public void setCantidadCiudades(int
cantidadCiudades){
this.cantidadCiudades = cantidadCiudades;
}
public int getCantidadCiudades() {
return cantidadCiudades;
}
public boolean insertarCiudad(Ciudad ciudad) {
if (cantidadCiudades < max) {
listaCiudades[cantidadCiudades] = ciudad;
cantidadCiudades++;
return true;
} else {
return false;
}
}
public Ciudad getCiudadI(int i) {
if (i >= 0 && i < cantidadCiudades) {
return listaCiudades[i];
} else {
return null;
}
}
2.160

public String toString() {


String salida = "nombre pais= "+ nombre +
",idioma=" + idioma + ", cant habitantes="
+ cantidadHabitantes+ "Sus ciudades\n"
for(int i = 0; i < cantidadCiudades; i++){
salida=salida+listaCiudades[i].toString()+"\n";
}

return salida;
}
}

package cl.ucn.ei.pa.paisciudades.logica;

import cl.ucn.ei.pa.paisciudades.dominio.Pais;

public interface SistemaPaisCiudades {

public void ingresarPais(String nombre,


String idioma, int cantidadHabitantes,
int cantidadCiudades);

public void ingresarCiudadDeUnPais(


String nombrePais, String nombreCiudad,
String alcalde, int cantidadHabitantes);

public String obtenerDatosPaisCiudades();

}
2.161

package cl.ucn.ei.pa.paisciudades.logica;
import cl.ucn.ei.pa.paisciudades.dominio.*;
public class SistemaPaisCiudadesImpl implements
SistemaPaisCiudades {
private Pais pais;
public SistemaPaisCiudadesImpl() {
pais = null;
}

public void ingresarPais(String nombre, String idioma,


int cantidadHabitantes, int cantidadCiudades) {

pais = new Pais(nombre, idioma,


cantidadHabitantes, cantidadCiudades);
}

public void ingresarCiudadDeUnPais(


String nombrePais, String nombreCiudad,
String alcalde, int cantidadHabitantes){
Ciudad ciudad = new Ciudad(nombre, alcalde,
cantidadHabitantes);
if (pais!=null || ! pais.getNombre().equals(nombrePais){
pais.insertarCiudad(ciudad);
}
else{
throw new NullPointerException("No existe pais");
}
}
public String obtenerDatosPaisCiudades(String nombrePais){
if (pais!=null || ! pais.getNombre().equals(nombrePais){
return pais.toString();
}
else{
throw new NullPointerException ("No existe pais");
}
}

}
2.162
package cl.ucn.ei.pa.paisciudades.logica;
import ucn.StdOut;
import ucn.StdIn;
import cl.ucn.ei.pa.paisciudades.dominio.*;
public class App {
public static void
LeerCiudadesPais(SistemaPaisCiudades sistema){
StdOut.print("Cantidad de ciudades de Chile: ");
int N = StdIn.readInt();
sistema.ingresarPais("Chile","Espanol",18000000,N);
for (int i = 1; i <= N; i++) {
StdOut.print("Ingrese nombre ciudad: ");
String nombreCiudad = StdIn.readString();
StdOut.print("Ingrese Alcalde: ");
String alcalde = StdIn.readString();
StdOut.print("Ingrese cantidad habitantes: ");
int cantidadHabitantes = StdIn.readInt();
try { Que no exista espacio, no es una precondición en un contrato
boolean ingreso =
sistema.ingresarCiudadDeUnPais("Chile",
nombreCiudad, alcalde, cantidadHabitantes);
if (!ingreso){
StdOut.println("No hay espacio para ingresar ciudades");
}
} catch (NullPointerException ex) {
StdOut.println(ex.getMessage());
}
}
}
public static void main(String[] args) {
SistemaPaisCiudades sistema = new
SistemaPaisCiudadesImpl();
LeerCiudadesPais(sistema);
try {
StdOut.println(sistema.
obtenerDatosPaisCiudades("Chile"));
} catch (NullPointerException ex) {
StdOut.println(ex.getMessage());
}
}//Fin main
}//Fin App
2.163
Diagrama de objetos
c: Ciudad

nombre= Santiago
alcalde= Alessandri
cantidadHabitantes= 6000000

p: Pais
c: Ciudad
nombre = Chile
nombre= Antofagasta
idioma=Español
cantidadHabitantes=18000000 alcalde= Rojo
cantidadHabitantes= 400000

listaCiudades
cantCiudades= 3 c: Ciudad

nombre= Concepcion
alcalde= Ortiz
cantidadHabitantes= 1000000
2.164
Versión 2
Diagrama de clases del dominio de la aplicación

Pais
Ciudad
- String nombre - String nombre
- String idioma - String alcalde
- int cantidadHabitantes - int cantidadHabitantes
- ListaCiudades listaCiudades + Ciudad(String nombre,
String alcalde,
+ Pais(String nombre, String idioma, int cantidadHabitantes)

+ get y set()….
int cantidadHabitantes) + get y set()…
+ toString(): String + toString(): String
+ getListaCiudades(): ListaCiudades
*
+ ingresarCiudad(Ciudad c): boolean
1

No necesariamente usaremos el get del contenedor, ya ListaCiudades


que la responsabilidad de ingresar una ciudad del - Ciudad [] lc
país será el país. Por lo tanto, tendremos un método - int cantidadCiudades
- int max
ingresarCiudad que invoque el método + ListaCiudades(int max)
insertarCiudad del contenedor + getCantidadCiudades(): int
+ insertarCiudad(Ciudad ciudad): boolean
+ getCiudadI(int i): Ciudad
public boolean ingresarCiudad(Ciudad c){ + toString(): String
listaCiudades.insertarCiudad(c);
}
2.165
Diagrama de clases

<<interface>>
SistemaPaisCiudades
SistemaPaisCiudadesImpl + ingresarPaisCiudades(nombre,
idioma, cantidadhabitantes)
- Pais p + ingresarCiudadDeUnPais (
nombrePais, nombreCiudad,
alcalde, cantidadHabitantes)
+ obtenerDatosPaisCiudades (
nombrePais): String

1
Ciudad
Pais - String nombre
- String alcalde
- String nombre - int cantidadHabitantes
- String idioma + Ciudad(String nombre,
- int cantidadHabitantes String alcalde,
- ListaCiudades listaCiudades int cantidadHabitantes)
+ get y set()…
+ Pais(String nombre, String idioma,
int cantidadHabitantes) + toString(): String
+ get y set()….
+ toString(): String *
+ getListaCiudades(): ListaCiudades
1
+ ingresarCiudad(Ciudad c): boolean
ListaCiudades
- Ciudad [] lc
- int cantidadCiudades
- int max
+ ListaCiudades(int max)
+ getCantidadCiudades(): int
+ insertarCiudad(Ciudad ciudad): boolean
+ getCiudad (int i): Ciudad
+ toString(): String
2.166

package cl.ucn.ei.pa.paisciudades.dominio;

public class Ciudad {

private String nombre;


private String alcalde;
private int cantidadHabitantes;

public Ciudad(String nombre, String alcalde,


int cantidadHabitantes) {
this.nombre = nombre;
this.alcalde = alcalde;
this.cantidadHabitantes = cantidadHabitantes;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getAlcalde() {
return alcalde;
}
public void setAlcalde(String alcalde) {
this.alcalde = alcalde;
}
public int getCantidadHabitantes() {
return cantidadHabitantes;
}
public void setCantidadHabitantes(int cantidadHabitantes) {
this.cantidadHabitantes = cantidadHabitantes;
}
@Override
public String toString() {
return "Ciudad [nombre=" + nombre + ", alcalde=" +
alcalde + ", cantidadHabitantes=" +
cantidadHabitantes + "]";
}
}
2.167
package cl.ucn.ei.pa.paisciudades.dominio;
import cl.ucn.ei.pa.paisciudades.logica.ListaCiudades;
public class Pais {
private String nombre;
private String idioma;
private int cantidadHabitantes;
private ListaCiudades listaCiudades;
public Pais(String nombre, String idioma, int cantidadHabitantes,
cantidadCiudades){
this.nombre = nombre;
this.idioma = idioma;
this.cantidadHabitantes = cantidadHabitantes;
listaCiudades = new ListaCiudades(cantidadCiudades);
}
public final String getNombre() {
return nombre;
}
public final void setNombre(String nombre) {
this.nombre = nombre;
}
public final String getIdioma() {
return idioma;
}
public final void setIdioma(String idioma) {
this.idioma = idioma;
}
public final int getCantidadHabitantes() {
return cantidadHabitantes;
}
public final void setCantidadHabitantes(int cantidadHabitantes){
this.cantidadHabitantes = cantidadHabitantes;
}
public String toString() {
String salida = "nombre pais= "+ nombre +
",idioma=" + idioma + ", cant habitantes="
+ cantidadHabitantes+ "Sus ciudades\n"
for(int i = 0; i < cantidadCiudades; i++){
salida=salida+listaCiudades.getCiudad(i).toString()+"\n";
}
return salida;
}
public ListaCiudades getListaCiudades() {
return listaCiudades;
}
public boolean ingresarCiudad(Ciudad c){
listaCiudades.insertarCiudad(c);
}
}
2.168

package cl.ucn.ei.pa.paisciudades.logica;
import cl.ucn.ei.pa.paisciudades.dominio.Ciudad;
public class ListaCiudades {
private Ciudad[] lc;
private int cantidadCiudades;
private int max;
public ListaCiudades(int max) {
lc = new Ciudad[max];
cantidadCiudades = 0;
this.max = max;
}
public int getCantidadCiudades() {
return cantidadCiudades;
}
public void setCantidadCiudades(int cantidadCiudades){
this.cantidadCiudades = cantidadCiudades;
}
public boolean insertarCiudad(Ciudad ciudad) {
if (cantidadCiudades < max) {
lc[cantidadCiudades] = ciudad;
cantidadCiudades++;
return true;
} else {
return false;
}
}
public Ciudad getCiudad (int i) {
if (i >= 0 && i < cantidadCiudades) {
return lc[i];
} else {
return null; Para imprimir el contenedor, es mejor construir
} el método toString en vez del que se obtiene con
} Eclipse o NetBeans. La idea es ir obteniendo
@Override elemento por elemento del contendor
public String toString(){
return "ListaCiudades [" + (lc != null ? "lc=" +
Arrays.toString(lc) + ", " : "") +
"cantidadCiudades="+ cantidadCiudades + ", max=" +
max + "]";
}
}//Fin ListaCiudades
2.169

package cl.ucn.ei.pa.paisciudades.logica;

public interface SistemaPaisCiudades {

public void ingresarPais(String nombre, String idioma,


int cantidadHabitantes, int cantidadCiudades);

public boolean ingresarCiudadDeUnPais(


String nombrePais, String nombreCiudad
String alcalde, int cantidadHabitantes);

public String obtenerDatosPaisCiudades(


String nombrePais);
}

package cl.ucn.ei.pa.paisciudades.logica;

import cl.ucn.ei.pa.paisciudades.dominio.*;

public class SistemaPaisCiudadesImpl implements


SistemaPaisCiudades{
private Pais pais;

public SistemaPaisCiudadesImpl() {
pais = null;
}

public void ingresarPais(String nombre, String idioma,


int cantidadHabitantes, int cantidadCiudades){

this.pais=new Pais(nombre,idioma,
cantidadHabitantes,cantidadCiudades);
}
2.170

public boolean ingresarCiudadDeUnPais(


String nombrePais, String nombreCiudad,
String alcalde, int cantidadHabitantes){
Ciudad ciudad = new Ciudad(nombreCiudad, alcalde,
cantidadHabitantes);
if (pais!=null || !pais.getNombre().equals(nombrePais)){

boolean ingreso = pais.ingresarCiudad(ciudad);


//La responsabilidad del ingreso de la ciudad como
//ciudad del país es del pais

//La otra forma es usar el contenedor.


//Esto funciona, pero no le estamos dando la
//responsabilidad al pais
boolean ingreso =
pais.getListaCiudades().insertarCiudad(ciudad);

return ingreso;
}
else{
throw new NullPointerException ("No existe pais");
}
}

public String obtenerDatosPaisCiudades(


String nombrePais){
if (pais!=null|| !pais.getNombre().equals(nombrePais)){
return pais.toString();
}
else{
throw new NullPointerException ("No existe pais");
}
}
}
2.171

package cl.ucn.ei.pa.paisciudades.logica;
import ucn.StdOut;
import ucn.StdIn;
import cl.ucn.ei.pa.paisciudades.dominio.*;
import cl.ucn.ei.pa.paisciudades.logica.SistemaPaisCiudades;
import cl.ucn.ei.pa.paisciudades.logica.SistemaPaisCiudadesImpl;
public class App {
public static void LeerCiudadesPais(
SistemaPaisCiudades sistema) {
StdOut.print("Ingrese cantidad ciudades Chile: ");
int N = StdIn.readInt();
sistema.ingresarPais("Chile","Espanol",17000000, N);
for (int i = 1; i <= N ; i++) {
StdOut.print("Ingrese nombre ciudad: ");
String nombre = StdIn.readString();
StdOut.print("Ingrese Alcalde: ");
String alcalde = StdIn.readString();
StdOut.print("Ingrese cantidad habitantes: ");
int cantidad = StdIn.readInt();
try {
boolean ingreso =
sistema.ingresarCiudadDeUnPais("Chile",
nombre, alcalde, cantidad);
if(!ingreso){
StdOut.println("No se ingreso ciudad.
No hay espacio");
}
catch NullPointerException ex) {
StdOut.println(ex.getMessage());
}
}
}
2.172

public static void main(String[] args) {


SistemaPaisCiudades sistema=new SistemaPaisCiudadesImpl();
LeerCiudadesPais(sistema);

try {
StdOut.println(
sistema.obtenerDatosPaisCiudades("Chile"));
} catch (NullPointerException ex) {
StdOut.println(ex.getMessage());
}

}//Fin main

}//Fin App
2.173
Ejemplo 4

Se desea construir un programa que maneje información de países y de


ciudades. Un país está relacionado con varias ciudades; una ciudad está
relacionada con un único país.

Datos asociados a un país son:


 Nombre del país.
 Cantidad de habitantes.
 Idioma que se habla (sólo uno).
 Continente en que se encuentra.

Datos asociados a una ciudad son:


 Nombre de la ciudad.
 Cantidad de universidades que tiene la ciudad.
 Cantidad de museos que tiene la ciudad.

Se pide, un programa que haga:


a) Ingreso de datos de países y ciudades.
b) Dado el nombre del país, encontrar el nombre de las ciudades
relacionadas.
c) Cantidad de países europeos (Continente = “Europa”).
d) Indicar el nombre del país que tiene mayor cantidad de habitantes.
e) Dado el nombre de una ciudad encontrar los datos del país relacionado.

Modelo del dominio


1 1..*
País Ciudad
 Nombre tiene  Nombre
 Cantidad de habitantes  Cantidad de universidades
 Idioma  Cantidad de museos
 Continente
2.174
Contratos
Suponiendo que los datos se leen de la siguiente forma:
1°. Cantidad de países
2°. Por cada país los datos del país, incluyendo la cantidad de ciudades del
país
3°. Por cada ciudad del país, los datos de la ciudad
Los contratos asociados al ingreso de los datos serían:
Operación Ingresar país (nombre, cantidad habitantes, idioma,
continente, cantidad de ciudades)
Descripción Se ingresa un país a la lista general de países

Precondiciones

Postcondiciones País ingresado a la lista general de países

Que exista espacio en el contenedor,


no es una precondición

Operación Ingresar ciudad (nombre, cantidad universidades, cantidad


museos)
Descripción Se ingresa una ciudad a la lista general de ciudades
Precondiciones

Postcondiciones Ciudad ingresada a la lista general de ciudades

Operación Asociar país ciudad (nombre pais, nombre ciudad)


Descripción Se asocia ciudad con país y el país con la ciudad
Precondiciones  Que exista el país
 Que exista la ciudad
Postcondiciones Asociaciones hechas entre país y ciudad:
 Ciudad ingresada a la lista de ciudades del país
 El país queda asociado como país de la ciudad
2.175
El resto de los contratos son:

Operación Encontrar ciudades de un país (nombre país)


Descripción Se obtienen los datos de las ciudades asociadas de un país

Precondiciones Que exista el país


Postcondiciones

Operación Obtener cantidad países europeos


Descripción Se obtiene la cantidad de países europeos
Precondiciones
Postcondiciones

Operación Obtener datos del país con más habitantes


Descripción Se obtienen los datos del país con la mayor cantidad de
habitantes

Precondiciones
Postcondiciones

Operación Encontrar el país de una ciudad (nombre ciudad)


Descripción Se obtiene los datos del país de una determinada ciudad

Precondiciones Que exista la ciudad


Postcondiciones
2.176
Diagrama de clases del domínio de la aplicación

1
Pais Ciudad
- String nombre - String nombre
- int cantidadHabitantes - int cantidadUniversidades
- String idioma - int cantidadMuseos
- String continente - Pais pais
- ListaCiudades listaCiudades + Ciudad()
+ Pais(String nombre, int cantidadHabitantes, + get y set …
String idioma, String continente) + setPais()
+ get y set…
+ getListaCiudades(): ListaCiudades
+ getPais(): Pais
+ toString():String + toString(): String
+ ingresarCiudad(Ciudad ciudad)
*
* Recuerde que la responsabilidad de
ingresar la ciudad como ciudad del país es
del país

1
ListaPaises ListaCiudades
- Pais [] lp
- int cantidadPaises
- Ciudad [] lc
- int max - int cantidadCiudades
- int max
+ ListaPaises(int max) + ListaCiudades(int max)
+ ingresarPais(Pais pais): boolean + ingresarCiudad(
+ buscarPais(String nombre): Pais Ciudad ciudad):boolean
+ getCantidadPaises(): int + buscarCiudad(String nombre):
+ getPais (int i): Pais Ciudad
+ toString():String + getCantidadCiudades():int
+ getCiudad (int i): Ciudad
+ toString():String
2.177
Diagrama de clases <<interface>>
SistemaPaisesCiudades
<<implements>>
+ ingresarPais(nombre, habitantes, idioma,
SistemaPaisesCiudadesImpl Continente, cantidadCiudades): boolean
+ingresarCiudad(nombre, universidades, museos):boolean
+asociarPaisCiudad(nombrePais, nombreCiudad)
- ListaPaises listaPaises
+ encontrarCiudadesPais(nomPais):String
- ListaCiudades listaCiudades + obtenerCantidadPaisesEuropeos():int
+ obtenerDatosPaisMasHabitantes(): String
+encontrarPaisDeUnaCiudad(nomCiudad):String

1
Pais Ciudad
- String nombre
- String nombre
- int cantidadUniversidades
- int cantidadHabitantes
- int cantidadMuseos
- String idioma
- Pais pais
- String continente
+ Ciudad(String nombre,
- ListaCiudades listaCiudades int cantidadUniversidades,
+ Pais(String nombre, int cantidadHabitantes, int cantidadMuseos)
String idioma, String continente) + get y set …
+ get y set… + setPais(Pais pais)
+ getListaCiudades(): ListaCiudades + getPais(): Pais
+ toString():String + toString():String
+ ingresarCiudad(Ciudad ciudad)
*

*
1 1
ListaPaises
- Pais [] lp ListaCiudades
- int cantidadPaises - Ciudad [] lc
-int max - int cantidadCiudades
+ ListaPaises(int max) - int max
+ ingresarPais(Pais pais): boolean + ListaCiudades(int max)
+ buscarPais(String nombre): Pais + ingresarCiudad(
+ getCantidadPaises(): int Ciudad ciudad):boolean
+ getPais (int i): Pais + buscarCiudad(String nombre):
Ciudad
+ toString():String + getCantidadCiudades():int
+ getCiudad (int i): Ciudad
+ toString():String

1
2.178

package cl.ucn.ei.pa.sistemapaisesciudades.dominio;

public class Ciudad {


private String nombre;
private int cantidadUniversidades;
private int cantidadMuseos;
private Pais pais;

public Ciudad(String nombre, int cantidadUniversidades,


int cantidadMuseos) {
this.nombre = nombre;
this.cantidadUniversidades = cantidadUniversidades;
this.cantidadMuseos = cantidadMuseos;
pais = null;
}

public String getNombre() {


return nombre;
}

public void setNombre(String nombre) {


this.nombre = nombre;
}

public int getCantidadUniversidades() {


return cantidadUniversidades;
}

public void setCantidadUniversidades(int cantidadUniversidades) {


this.cantidadUniversidades = cantidadUniversidades;
}

public int getCantidadMuseos() {


return cantidadMuseos;
}

public void setCantidadMuseos(int cantidadMuseos) {


this.cantidadMuseos = cantidadMuseos;
}
2.179

public Pais getPais() {


return pais;
}

public void setPais(Pais pais) {


this.pais = pais;
}

//@Override
public String toString() {
return "Ciudad [" + (nombre != null ? "nombre=" + nombre +
", " : "") +
"cantidadUniversidades="+ cantidadUniversidades +
", cantidadMuseos=" + cantidadMuseos + "]";
}

package cl.ucn.ei.pa.sistemapaisesciudades.dominio;
import cl.ucn.ei.pa.sistemapaisesciudades.logica.ListaCiudades;

public class Pais {


private String nombre;
private int cantidadHabitantes;
private String idioma;
private String continente;
private ListaCiudades listaCiudades;
private int cantidadCiudades;

public Pais(String nombre, int cantidadHabitantes, String idioma,


String continente, int cantidadCiudades) {
this.nombre = nombre;
this.cantidadHabitantes = cantidadHabitantes;
this.idioma = idioma;
this.continente = continente;
this.cantidadCiudades = cantidadCiudades;
listaCiudades = new ListaCiudades(cantidadCiudades);
}
2.180

public String getNombre() {


return nombre;
}

public void setNombre(String nombre) {


this.nombre = nombre;
}

public int getCantidadHabitantes() {


return cantidadHabitantes;
}

public void setCantidadHabitantes(int cantidadHabitantes) {


this.cantidadHabitantes = cantidadHabitantes;
}

public String getIdioma() {


return idioma;
}

public void setIdioma(String idioma) {


this.idioma = idioma;
}

public String getContinente() {


return continente;
}

public void setContinente(String continente) {


this.continente = continente;
}

public ListaCiudades getListaCiudades() {


return listaCiudades;
}

public void ingresarCiudad(Ciudad ciudad) {


this.listaCiudades.ingresarCiudad(ciudad);
}
2.181

public String toString(){


String salida = nombre;
for (int i=0; i<listaCiudades.getCantidadCiudades(); i++){
salida = salida + listaCiudades.getCiudadI(i).toString();
}
return salida;
}

package cl.ucn.ei.pa.sistemapaisesciudades.logica;

import cl.ucn.ei.pa.sistemapaisesciudades.dominio.Ciudad;

public class ListaCiudades {


private Ciudad []lc;
private int cantidadCiudades;
private int max;

public ListaCiudades(int max){


lc = new Ciudad [max];
cantidadCiudades = 0;
this.max = max;
}

public boolean ingresarCiudad(Ciudad ciudad){


if (cantidadCiudades < max){
lc[cantidadCiudades]= ciudad;
cantidadCiudades ++;
return true;
}
else{
return false;
}
}

public int getCantidadCiudades(){


return cantidadCiudades;
}
2.182
public Ciudad getCiudad (int i){
if (i >=0 && i < cantidadCiudades){
return lc[i];
}
else{
return null;
}
}

public Ciudad buscarCiudad(String nombre){


int i;
for(i = 0; i < cantidadCiudades; i++){
if (lc[i].getNombre().equals(nombre)){
break;
}
}
if (i == cantidadCiudades){
return null;
}
else{
return lc[i];
}
}

public String toString() {


String salida = "";
for (int i = 0; i < cantidadCiudades; i++){
salida = salida + lc[i].toString();
}
return salida;
}

}
2.183
package cl.ucn.ei.pa.sistemapaisesciudades.logica;

import cl.ucn.ei.pa.sistemapaisesciudades.dominio.Pais;

public class ListaPaises {


private Pais []lp;
private int cantidadPaises;
private int max;

public ListaPaises(int max){


lp = new Pais [max];
cantidadPaises = 0;
this.max = max;
}

public boolean ingresarPais(Pais pais){


if (cantidadPaises < max){
lp[cantidadPaises]= pais;
cantidadPaises ++;
return true;
}
else{
return false;
}
}

public int getCantidadPaises(){


return cantidadPaises;
}

public Pais getPais (int i){


if (i >=0 && i < cantidadPaises){
return lp[i];
}
else{
return null;
}
}
2.184
public Pais buscarPais(String nombre){
int i;
for(i = 0; i < cantidadPaises; i++){
if (lp[i].getNombre().equals(nombre)){
break;
}
}
if (i == cantidadPaises){
return null;
}
else{
return lp[i];
}
}

public String toString() {


String salida = "";
for (int i = 0; i < cantidadPaises; i++){
salida = salida + lp[i].toString();
}
return salida;
}
}

package cl.ucn.ei.pa.sistemapaisesciudades.logica;

public interface SistemaPaisesCiudades {


public boolean ingresarPais(String nombre, int cantidadHabitantes,
String idioma, String continente, int cantidadCiudades);
public boolean ingresarCiudad(String nombre,
int cantidadUniversidades, int cantidadMuseos);
public void asociarPaisCiudad (String nombrePais,
String nombreCiudad);
public int obtenerCantidadPaisesEuropeos();
public String obtenerDatosPaisMasHabitantes();
public String encontrarPaisDeUnaCiudad(String nombreCiudad);
public String encontrarCiudadesPais(String nombrePais);
}
2.185
package cl.ucn.ei.pa.sistemapaisesciudades.logica;

import cl.ucn.ei.pa.sistemapaisesciudades.dominio.*;

public class SistemaPaisesCiudadesImpl implements SistemaPaisesCiudades{

private ListaPaises listaPaises;


private ListaCiudades listaCiudades;

public SistemaPaisesCiudadesImpl(int cantidadPaises) {


listaPaises = new ListaPaises(cantidadPaises);
listaCiudades = new ListaCiudades(10000);
}

public boolean ingresarPais(String nombre, int cantidadHabitantes,


String idioma, String continente, int cantidadCiudades){
Pais pais = new Pais(nombre, cantidadHabitantes, idioma,
continente, cantidadCiudades);
boolean ingreso = listaPaises.ingresarPais(pais);
return ingreso;
}

public boolean ingresarCiudad(String nombre,


int cantidadUniversidades, int cantidadMuseos){
Ciudad ciudad = new Ciudad (nombre, cantidadUniversidades,
cantidadMuseos);
boolean ingreso = listaCiudades.ingresarCiudad(ciudad);
return ingreso;
}

public void asociarPaisCiudad (String nombrePais,


String nombreCiudad){
Pais pais = listaPaises.buscarPais(nombrePais);
Ciudad ciudad = listaCiudades.buscarCiudad(nombreCiudad);
if (pais != null && ciudad != null){
ciudad.setPais(pais);
pais.getListaCiudades().ingresarCiudad(ciudad);
}
else{
throw new NullPointerException("No existe ciudad y/o pais");
}
}
public int obtenerCantidadPaisesEuropeos(){
2.186
int contadorPaisesEuropeos = 0;
for (int i = 0; i < listaPaises.getCantidadPaises(); i++){
if (listaPaises.getPais(i).getContinente().
equals("Europa")) {
contadorPaisesEuropeos++;
}
}
return contadorPaisesEuropeos;
}

public String obtenerDatosPaisMasHabitantes (){


int mayor = -1;
Pais paisMayor= null;
for (int i = 0; i < listaPaises.getCantidadPaises(); i++){
Pais pais = listaPaises.getPais(i);
if (pais.getCantidadHabitantes()> mayor) {
mayor = pais.getCantidadHabitantes();
paisMayor = pais;
}
}
if (paisMayor!= null){
return paisMayor.toString();
}
else {
return "no existe pais con mas habitantes";
}
}

public String encontrarPaisDeUnaCiudad(String nombre){


Ciudad ciudad = listaCiudades.buscarCiudad(nombre);
if (ciudad != null){
return ciudad.getPais().getNombre();
}
else{
throw new NullPointerException("No existe ciudad");
}
}
2.187
public String encontrarCiudadesPais(String nombrePais){
Pais pais = listaPaises.buscarPais(nombrePais);
if (pais != null){
return pais.getListaCiudades().toString();
}
else{
throw new NullPointerException("No existe el pais");
}
}

package cl.ucn.ei.pa.sistemapaisesciudades.logica;

import ucn.StdOut;
import ucn.StdIn;
import cl.ucn.ei.pa.sistemapaisesciudades.logica.SistemaPaisesCiudades;
import cl.ucn.ei.pa.sistemapaisesciudades.logica.SistemaPaisesCiudadesImpl;

public class App {

public static void main(String[] args) {


StdOut.print("Ingrese cantidad de paises: ");
int cantidadPaises = StdIn.readInt();
SistemaPaisesCiudades sistema =
new SistemaPaisesCiudadesImpl(cantidadPaises);

LeerPaisesCiudades(sistema, cantidadPaises);

int cantidad = sistema.obtenerCantidadPaisesEuropeos();


StdOut.println("Cantidad de paises europeos: "+ cantidad);

StdOut.println("Pais mas habitantes " +


sistema.obtenerDatosPaisMasHabitantes());

StdOut.print("nombre ciudad para buscar el pais asociado ");


String nombreCiudad = StdIn.readString();
2.188

try{
StdOut.println("Pais " +
sistema.encontrarPaisDeUnaCiudad(nombreCiudad));
} catch (NullPointerException ex) {
StdOut.println(ex.getMessage());
}

StdOut.print("nombre pais para saber ciudades asociadas ");


String nombrePais = StdIn.readString();
try{
StdOut.println("Ciudades " +
sistema.encontrarCiudadesPais(nombrePais));
} catch (NullPointerException ex) {
StdOut.println(ex.getMessage());
}
}

public static void LeerPaisesCiudades(SistemaPaisesCiudades sistema,


int cantidadPaises) {
for(int i = 0; i < cantidadPaises; i++){ //Por cada pais
StdOut.println("Ingrese datos de un pais ");
StdOut.print("Nombre pais: ");
String nombrePais = StdIn.readString();
StdOut.print("Idioma pais: ");
String idioma = StdIn.readString();
StdOut.print("Cantidad de habitantes pais ");
int cantidadHabitantes = StdIn.readInt();
StdOut.print("Ingrese continente: ");
String continente = StdIn.readString();
StdOut.print("Ingrese cantidad ciudades del pais " +
nombrePais);
int cantidadCiudades = StdIn.readInt();

boolean ingreso = sistema.ingresarPais(nombrePais,


cantidadHabitantes, idioma, continente,
cantidadCiudades);
2.189

//Se ingresa a la lista general de paises


if (!ingreso){
StdOut.println("No se ingreso el pais.
No hay espacio");
}
else{
for (int j = 0; j < cantidadCiudades ; j++){
//Para cada ciudad del pais
StdOut.println("Ingrese datos de una ciudad ");
StdOut.print("Nombre ciudad: ");
String nombreCiudad = StdIn.readString();
StdOut.print("Cantidad de universidades: ");
int cantidadUniversidades = StdIn.readInt();
StdOut.print("Cantidad de museos: ");
int cantidadMuseos = StdIn.readInt();

ingreso = sistema.ingresarCiudad(nombreCiudad,
cantidadUniversidades, cantidadMuseos);
//Se ingresa la ciudad a la lista de todas
//las ciudades
if (!ingreso){
StdOut.println("No se ingreso la ciudad.
No hay espacio");
}
else{
try{
sistema.asociarPaisCiudad(nombrePais,
nombreCiudad);
//Se asocia el pais y la ciudad
}catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}
}
}
}
}
}

}
2.190
Si los datos se leen de la siguiente forma:
1°. Cantidad de países, cantidad de ciudades
2°. Por cada país los datos del país
3°. Por cada ciudad, los datos de la ciudad, incluyendo el nombre del pais
al que pertenece
Los contratos ingresarCiudad y asociarPaisCiudad, asociados al ingreso de
los datos serían reemplazados por los siguientes:

Operación Ingresar ciudad de un pais(nombre ciudad,


cantidad universidades, cantidad museos, nombre
país)
Descripción  Se ingresa una ciudad a la lista general de
ciudades
 Se asocia la ciudad con el país:
 La ciudad se ingresa a la lista de ciudades del
país
 La ciudad queda asociada con el país
Precondiciones Que exista el país
Postcondiciones  Ciudad ingresada en la lista general de ciudades
 Ciudad ingresada a la lista de ciudades del pais
 Ciudad asociada con el país
2
2.191
Código que cambia
package cl.ucn.ei.pa.sistemapaisesciudades.logica;

public interface SistemaPaisesCiudades {

public boolean ingresarPais(String nombre, int cantidadHabitantes,


String idioma, String continente);

public boolean ingresarCiudadDeUnPais(String nombre,


int cantidadUniversidades, int cantidadMuseos,
String nombrePais);

public int obtenerCantidadPaisesEuropeos();

public String paisMasHabitantes();

public String paisDeterminadaCiudad(String nombreCiudad);

public String ciudadesDeterminadoPais(String nombrePais);


}

Parte de Clase SistemaPaisesCiudadesImpl


public class SistemaPaisesCiudadesImpl implements
SistemaPaisesCiudades {
private ListaPaises listaPaises;
private ListaCiudades listaCiudades;
public SistemaPaisesCiudadesImpl(int cantidadPaises,
int cantidadCiudades) {
listaPaises = new ListaPaises(cantidadPaises);
listaCiudades = new ListaCiudades(cantidadCiudades);
}
2.192

public boolean ingresarCiudadDeUnPais(String nombre,


int cantidadUniversidades, int cantidadMuseos,
String nombrePais){

Pais pais = listaPaises.buscarPais(nombrePais);


if(pais== null){
throw new NullPointerException("No existe el pais");
}
Ciudad ciudad = new Ciudad (nombre, cantidadUniversidades,
cantidadMuseos);
boolean ingreso = listaCiudades.ingresarCiudad(ciudad);
ciudad.setPais(pais);
ingreso = pais.getListaCiudades().ingresarCiudad(ciudad);
return ingreso;
}
……

Parte de la App
public static void main(String[] args) {
StdOut.print("Ingrese cantidad de paises: ");
int cantidadPaises = StdIn.readInt();
StdOut.print("Ingrese cantidad de ciudades: ");
int cantidadCiudades = StdIn.readInt();
SistemaPaisesCiudades sistema =
new SistemaPaisesCiudadesImpl(cantidadPaises,
cantidadCiudades);

LeerPaises(sistema, cantidadPaises);
LeerCiudades(sistema, cantidadCiudades);
……
2.193

public static void LeerCiudades(SistemaPaisesCiudades sistema,


int cantidadCiudades){

for (int j = 0; j < cantidadCiudades ; j++){


//Para cada ciudad
StdOut.println("Ingrese datos de una ciudad ");
StdOut.print("Nombre ciudad: ");
String nombreCiudad = StdIn.readString();
StdOut.print("Cantidad de universidades: ");
int cantidadUniversidades = StdIn.readInt();
StdOut.print("Cantidad de museos: ");
int cantidadMuseos = StdIn.readInt();
StdOut.print("nombre del pais al que pertenece: ");
String nombrePaisPertenece = StdIn.readString();
try{
boolean ingreso =
sistema.ingresarCiudadDeUnPais(nombreCiudad,
cantidadUniversidades, cantidadMuseos,
nombrePaisPertenece);
//Se ingresa la ciudad a la lista de todas
//las ciudades
if(!ingreso){
StdOut.println("No se ingreso la ciudad.
No hay espacio");
}
}
catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}
}
}
2.194

public static void LeerPaises(SistemaPaisesCiudades sistema,


int cantidadPaises) {

for(int i = 0; i < cantidadPaises; i++){ //Por cada pais


StdOut.println("Ingrese datos de un pais ");
StdOut.print("Nombre pais: ");
String nombrePais = StdIn.readString();
StdOut.print("Idioma pais: ");
String idioma = StdIn.readString();
StdOut.print("Cantidad de habitantes pais ");
int cantidadHabitantes = StdIn.readInt();
StdOut.print("Ingrese continente: ");
String continente = StdIn.readString();

boolean ingreso= sistema.ingresarPais(nombrePais,


cantidadHabitantes, idioma, continente);
//Se ingresa a la lista general de paises
if(!ingreso){
StdOut.println("No se ingreso el pais.
No hay espacio");
}
}
}
2.195
2.9. Herencia en Java
Ejemplo
Se tiene que construir una aplicación para manejar a empleados y estudiantes. De los
empleados se sabe el rut, nombre, dirección, sueldo y fecha de nacimiento. De los
estudiantes, rut, nombre, dirección, número de matrícula y carrera.
Se podría tener una jerarquía de clases formada por:
 Una clase Persona con todos los atributos y métodos comunes entre Empleado y
Estudiante y
 Dos clases (Empleado y Estudiante) que heredean desde Persona, junto a la
correspondiente definición de las propiedades, variables de instancia, y métodos,
de cada una de ellas.

Como las clases Empleado y Estudiante heredan propiedades de la superclase


Persona, los objetos asociados a estas clases tienen las propiedades definidas para la
clase propiamente tal, y las heredadas de la clase Persona.

Persona

Empleado Estudiante
2.9.1. Concepto
 Se permite definir una nueva clase B, como una extensión de una clase previa A.
 B se denomina subclase de A y A se denomina superclase de B
 B es la Clase derivada y A es la Clase base
 Una subclase típicamente aumenta o redefine la estructura existente y el
comportamiento de su superclase.
Ejemplos:
Figura

Rectángulo Triángulo Círculo

Cuenta Bancaria

Cuenta Corriente Cuenta de Ahorro


2.196
Retomemos el ejemplo de los empleados y estudiantes
Se tiene una jerarquía de clases, formada por una clase base (Persona) y dos clases
derivadas (Empleado y Estudiante), junto a la correspondiente definición de las
propiedades, variables de instancia, y métodos, de cada una de ellas.
Como las clases Empleado y Estudiante heredan propiedades de la superclase
Persona, los objetos asociados a estas clases tienen las propiedades definidas para la
clase propiamente tal, y las heredadas de la clase Persona.

Superclase Persona, con subclase Estudiante y Empleado

Persona

Estudiante Empleado

Persona
Variables de instancia:
- nombre
- direccion
- fechaNacimiento
- rut
Métodos:
- inicializarDatosPersona
- obtenerDatosPersona

Estudiante Empleado
Variables de instancia: Variables de instancia:
- numeroMatricula
- sueldo
- carrera
Métodos: Métodos:
- InicializarDatosEstudiante - IncializarDatosEmpleado
- obtenerCarrera - obtenerSueldo
- obtenerNumeroMatricula
2.197
Herencia de propiedades en una jerarquía de clases

Estudiante Estudiante
Variables de instancia: Variables de instancia:
- numeroMatricula - numeroMatricula
- carrera - carrera
Métodos: - rut
- inicializarDatosEstudiante - nombre
- obtenerCarrera - dirección
- obtenerNumeroMatricula - fechaNacimiento
+ Métodos:
- inicializarDatosEstudiante
Persona - obtenerCarrera
- obtenerNumeroMatricula
- inicializarDatosPersona
- obtenerDatosPersona

Empleado Empleado
Variables de instancia: Variables de instancia:
- sueldo - sueldo
Métodos: -rut
- inicializarDatosEmpleado - nombre
- obtenerSueldo - dirección
+ - fechaNacimiento
Métodos:
Persona - inicializarDatosEmpleado
- obtenerSueldo
- inicializarDatosPersona
- obtenerDstosPersona
+
La habilidad de un lenguaje para soportar la herencia,
Persona distingue a los
lenguajes orientados al objeto, de los lenguajes basados en objetos.

Las reglas de herencia, permiten que un objeto de una subclase B puede


aparecer, donde quiera que un objeto de una superclase A es esperado.
2.198
Herencia simple: Hay una única superclase.

Herencia Múltiple: Hay varias superclases.

¡ JAVA tiene herencia simple !

Se recomienda no más de 3 niveles

Las reglas de herencia en Java son:


 La herencia simple genera una jerarquía. En la raíz de la jerarquía se
encuentra la clase Object.
 Todas las clases, excepto la clase Object, tienen exactamente una
superclase.
 Una subclase hereda variables y métodos de su superclase.
 Una subclase puede declarar variables y métodos, diferentes de aquellos
heredados.
 Los métodos en la subclase, pueden redefinir a los métodos heredados
(“OVERRIDE”).
 Una variable heredada también se puede redefinir.

Visibilidad PROTECTED en una clase


Es una declaración que está visible solamente a la misma clase y a sus
subclases
A
- int a1 El constructor A es
- int a2
solo visible dentro de
protected # A(int a1, int a2)
+ get y set… la clase A y la subclase
B.
Es incorrecto tener por
ejemplo en el main
B new A(…)
- int b1
+ B(int b1)
+ get y set…
2.199
Ejemplo:
De la super clase los
public class Punto{ Punto atributos se colocan
- int x privados y los métodos
private int x; - int y pudieran ser protegidos
+Punto(int x,int y)
private int y;
Podríamos colocar los
public Punto(int x, int y){ atributos como
this.x = x; protected, pero se
this.y = y; decide se colocarlos
} Punto3D0 privados, porque para
- int z eso se tienen los get y
} + Punto3D0(int x, int y, int z)
set.

class Punto3D0 extends Punto {


private int z;
La rutina
public Punto3D0(int x, int y, int z) {
constructora
super(x,y); //Se ejecuta la rutina contructora del padre no se hereda
this.z = z;
} Si en vez de super (x,y), estuviera:
 this.x = x;
public Punto3D0() {
 this.y = y;
this(-1, -1, -1);
No compila:
}
 Como x e y son privados no se pueden ver, aunque se
}
hereden
 Se requiere el super
En JAVA, si la
cláusula extends es Aunque la visibilidad fuese protected para los atributos
omitida en la x e y, siempre se requiere invocar la rutina
declaración de una constructora del padre. Esto se hace a través del super
clase, ésta tendrá en en la rutina constructora del hijo
forma implícita a la
clase Object como su superclase inmediata, que es la raíz de la jerarquía de clases de
JAVA.

De esta manera, todas las clases son subclases directas o indirectas de la clase Object.
2.200
Notación
La representación de la herencia, de acuerdo a la notación utilizada por
UML (Unified Modeled Language - Lenguaje de Modelado Unificado)

Superclase

Subclase1 Subclase2

Ejemplos:
Cuenta
Bancaria

Cuenta Cuenta
Ahorro Corriente
2.201

Equipo

Intercambiador
Bomba Estanque
de Calor

Estanque Estanque
.......
Esférico a Presión

Figura

Rectángulo Triángulo Círculo

Cuadrado
2.202

Mensajes a super

Cuando existe sobreescritura de métodos y/o atributos, la palabra super


permite tener acceso a los miembros públicos y protegidos (métodos y
atributos) de la clase padre.

Si quiero obtener un atributo sobreescrito privado de la clase padre, se usa


super.getAtributo()

Cuando una subclase sobrescribe un método heredado, el nombre especial


super, permite que el método sobrescrito sea usado, es decir usar el método
del padre.

Dentro de una subclase, un mensaje a super, invoca el método que la


superclase debería usar para ese mensaje.

Ejemplo
A public class A {
- int dato private int dato;
+ A(int dato) public A(int dato) {
+ m1(int x): int this.dato = dato;
+ get y set()… }
public int getDato() {
StdOut.println("Pasa por getDato() del padre");
B return dato;
- int dato }
public void setDato(int dato) {
+ B(int dato, int dato1) this.dato = dato;
}
+ m1(int dato): int public int m1(int x) {
+ m2(): int StdOut.println("Pasa por m1 del padre");
+ get y set()… return x + 5;
}
}
2.203

public class B extends A{


private int dato;
public B(int dato, int dato1) {
super(dato);
this.dato = dato1;
}
public int getDato() {
StdOut.println("Pasa por getDato del hijo");
return dato;
}
public void setDato(int dato) {
this.dato = dato;
}
public int m1(int dato) {
StdOut.println("Pasa por m1 del hijo");
return super.m1(dato);//Invoca al m1 sobreescrito del padre
}
public int m2() {
StdOut.println("Pasa por m2");
return super.m1(3) + super.getDato();
//Invoca al m1 sobreescrito del padre y
//al dato sobreescrito del padre
}
}

public class App {


a:A
public static void main(String[] args) { dato=5
A a = new A(5);
B b = new B(3,2);
a
StdOut.println("a.m1(5)= " + a.m1(5));
StdOut.println("b.m1(2)= " + b.m1(2)); b:B
StdOut.println("b.m2()= " + b.m2()); dato (heredado)=3
} dato (de B) = 2
}

Se imprime
b
Pasa por m1 del padre
a.m1(5)= 10
Pasa por m1 del hijo
Pasa por m1 del padre
b.m1(2)= 7
Pasa por m2
Pasa por m1 del padre
Pasa por getDato() del padre
b.m2()= 11
2.204
Ejemplo: Se define la subclase Punto3D, que utiliza el constructor super para
inicializar las variables x e y, después imprime el punto en 3D resultante.
public class Punto {
private int x;
private int y;
public Punto(int x, int y){ Recuerde que los atributos de la
this.x = x;
super clase se colocan privados,
this.y = y;
} ya que para eso se tienen los
public int getX(){ métodos get y set asociados . Los
return x; métodos pudieran ser protegidos
}
public int getY(){
return y;
}
}

public class Punto3D extends Punto {


private int z;
public Punto3D(int x, int y, int z) {
//llamado al constructor Punto(x,y)
super(x, y);
//Se invoca el método que la superclase debería usar para este mensaje
this.z = z;
}
public int getZ(){
return z;
}
}
public class Punto3DConstruct {
public static void main(String args[]) {
Punto3D p = new Punto3D(10, 20, 30);
StdOut.println("x = " + p.getX() + " y = " + p.getY() + " z = " + p.getZ());
StdOut.println("p = " + p);
}
}

x = 10 y = 20 z = 30
p = Punto3D @ 1cc807
Resultado: Clase del Dirección
Objeto
2.205
Ejemplo
La clase Punto3D hereda de su superclase Punto la implementación del
método de la distancia para puntos en 2D. Necesita por lo tanto sobrescribir
esa definición con una nueva para puntos en 3D.
En la clase Punto3D hay sobrecarga de la distancia en 3D y hay redefinición
(sobrescritura) de la distancia en 2D. Si hay distintas versiones de un
public class Punto { método, se deben colocar todas en
private int x; Redefinición el diagrama de clases.
private int y; Los métodos en el diagrama de
clases deben llevar los parámetros
public Punto(int x, int y){
this.x=x;
this.y=y;
}
public int getX(){ Punto
return x;
} - int x
public int getY(){ - int y
return y;
} + Punto(int x, int y)
public double distancia + getX(): int
(int x, int y){ + getY(): int
StdOut.println("Primer método + distancia(int x, int y):double
distancia del padre Punto. + distancia (Punto p): double
Parametros: x,y");
int dx = this.x - x;
int dy = this.y - y;
return Math.sqrt(dx*dx + dy*dy); Punto3D
} - int z
public double distancia(Punto p){
System.out.println("Segundo + Punto3D (int x, int y, int z)
metodo distancia del padre + getZ():
Se imprime int
Pasa por m1 del padre
Punto. Parametros: Punto"); + distancia(int x, int y, int z):
a.m1(5)= 10
return this.distancia(p.x, p.y); Pasa por m1 del hijo double
} Pasa por m1 del padre
+ distancia(Punto3D otro):
b.m1(2)= 7
Si el objeto que invoca es de la clase Punto, se invoca el Pasa por m2 double
primer método de distancia de la clase Punto. Pasa por m1 del padre
Si el objeto que invoca es de la clase Punto3D, se invoca + distancia(int
Pasa por getDato()x,del
intpadre
y): double
b.m2()= 11
el tercer método de distancia de la clase Punto3D
}//Fin clase Punto Redefinición
2.206
public class Punto3D extends Punto{
private int z;

public Punto3D(int x, int y, int z) {


super(x, y);
this.z = z;
El super es necesario para invocar
} la rutina constructora del padre
public int getZ(){
return z;
}

public double distancia(int x, int y,int z) {


System.out.println("Primer metodo distancia del hijo
Punto3D. Parametros: x, y, z");

int dx = this.getX() - x;
//Se tiene que usar el getX(), porque es private
int dy = this.getY() - y;
int dz = this.z - z;
return Math.sqrt(dx*dx + dy*dy + dz*dz);
}

public double distancia(Punto3D otro) {


System.out.println("Segundo metodo distancia del hijo
Punto3D. Parametros: Punto3D");

return this.distancia(otro.getX(), otro.getY(), otro.z);


}
Si el objeto que invoca es de la clase Punto3D,
se invoca el primer método de distancia de la
clase Punto3D.
public double distancia(int x, int y) {
System.out.println("Tercer metodo distancia del hijo
Punto3D. Parametros: x, y");

double dx = (double)this.getX()/z -x;


double dy = (double)this.getY()/z -y;
return Math.sqrt(dx*dx + dy*dy);
}

}
2.207
public class Punto3DDist {
public static void main(String[] args) {
Punto3D p1 = new Punto3D(30, 40, 10);
Punto3D p2 = new Punto3D(0, 0, 0);
Punto p = new Punto(4, 6);
p2: Punto3D p: Punto p1: Punto3D
x=0 x=4 x = 30
y=0 y=6 y = 40
z=0 z = 10
StdOut.println("p1 = " + p1.getX() + ", " + p1.getY() +
", " + p1.getZ());
StdOut.println("p2 = " + p2.getX() + ", " + p2.getY() +
", " + p2.getZ());
StdOut.println("p = " + p.getX() + ", " + p.getY());
StdOut.println("------------------------------");
StdOut.println("p1.distancia(p2) = " + p1.distancia(p2));
StdOut.println("------------------------------");
StdOut.println("p1.distancia(4, 6)=" + p1.distancia(4,6));
StdOut.println("------------------------------");
StdOut.println("p1.distancia(p) = " + p1.distancia(p));
}
}

Se imprime

p1 = 30, 40, 10
p2 = 0, 0, 0
p = 4, 6
------------------------------
Segundo metodo distancia del hijo Punto3D. Parametros:
Punto3D
Primer metodo distancia del hijo Punto3D. Parametros: x, y, z
p1.distancia(p2) = 50.99019513592785
------------------------------
Tercer metodo distancia del hijo Punto3D. Parametros: x, y
p1.distancia(4, 6) = 2.23606797749979
------------------------------
Segundo metodo distancia del padre Punto. Parametros: Punto
Tercer metodo distancia del hijo Punto3D. Parametros: x, y
p1.distancia(p) = 2.23606797749979
2.208
Notas:
Hay una tensión importante, entre la herencia y el encapsulamiento.

El uso de la herencia expone alguno de los secretos de la clase


heredada.

En la práctica, esto significa que para comprender el significado de una


clase particular, a menudo se deben estudiar todas sus superclases,
incluyendo a veces su vista interna.

2.9.2. Selección de método dinámica (Polimorfismo)

Ejemplo:
Se desea construir una aplicación que manipula círculos, triángulos y rectángulos en
un sistema gráfico, en base a las siguientes operaciones:
 Indicar ubicación de un círculo, de un triángulo y de un rectángulo.
 Dibujar un círculo, un triángiulo y un rectángulo.
 Imprimir un círculo, un triángiulo y un rectángulo.
 Rotar un círculo, un triángiulo y un rectángulo.
 Indicar el color de un círculo, un triángulo y un rectángulo.

Sabemos que si es un triángulo el rotar, el dibujar y el imprimir se hacen para un


triángulomanera. Idem para el círculo y el rectángulo
Ya sabemos que las características del modelo orientado al objeto permiten definir
clases y hacer explícitas las propiedades comunes de las clases mediante el
mecanismo de la herencia. Se tiene entonces la siguiente jerarquía de clases como
solución al problema.
2.209
Figura
Variables de instancia:
 Centro
 Color
Métodos:
 Ubicar
 Dibujar
 Imprimir
 Rotar
 Color

Figura

Rectángulo Triángulo Círculo

Rectángulo Triángulo Circulo


Variables de instancia: Variables de instancia: Variables de instancia:
 Vértices  Limites  Radio
Métodos:
Métodos:  Dibujar Métodos:
 Dibujar  Imprimir  Dibujar
 Imprimir  Rotar  Imprimir
 Rotar  Rotar

Debe hacerse notar, que las clases Rectángulo, Triángulo y Círculo, sobrescriben los
procedimientos Dibujar, Imprimir y Rotar, los que son específicos para cada una de
las clases. En esta solución, según sea el tipo de la información que se está
procesando, se ejecuta el procedimiento adecuado para la situación que se presenta;
por ejemplo, si el método Rotar se aplica a un objeto de la clase Rectángulo, el método
asociado a esa clase es ejecutado.

Para extender o reusar el sistema, basta con crear una nueva subclase dentro de la
jerarquía de clases mostrada anteriormente, que agregue o modifique propiedades
de la superclase, sin necesidad de modificar las clases existentes.
2.210
Por ejemplo, si se desea incorporar la clase Cuadrado al sistema, sólo se modifica
la definición de clases anterior.

La nueva clase sobrescribe los métodos Dibujar y Rotar, por procedimientos


específicos que se aplican solamente a las instancias de la clase Cuadrado.

Figura

Rectángulo Triángulo Círculo

Rotar
Cuadrado Dibujar

Concepto de polimorfismo
Cuando se aplica un método a un objeto, el tipo del objeto se comprueba
durante la compilación, para asegurarse de que el método llamado existe en
la clase declarada.

Durante la ejecución, el objeto puede corresponder a alguna subclase del


objeto declarado. En este caso y cuando la subclase sobreescriba (redefina)
el método al que se llama, se utiliza la instancia real para decidir a qué
método llamar.

Polimorfismo = “LATE BINDING”


(enlace tardío)
2.211
Polimorfismo en Java:
 En Java todas las variables son polimórficas.
 Una variable declarada de una cierta clase, puede mantener valores de
cualquiera de sus subclases.

Ejemplo: Dos clases tienen una relación subclase/superclase, con un único método
que se sobrescribe en la subclase
A

public class A { + callme()


public void callme() {
StdOut.println("Inside A's callme method");
B
}
} + callme()

public class B extends A{ El objeto corresponde al de


public void callme(){ la subclase. Recuerde que
StdOut.println("Inside B's callme method"); la regla de herencia dice
} que un objeto de una
} subclase B puede aparecer
donde quiera que un objeto
public class Dispatch {
de una superclase A es
public static void main(String args[]) {
esperado
A a = new B(); //a pertenece a la clase A.
// Se ha almacenado una referencia a una
//instancia de la clase B en ella. Callme tiene que estar
a.callme(); //invoca a callme de la clase B.
declarado en la clase A.
}
Esto se chequea en tiempo
}
Resultado de compilación
Inside B’s callme method

El polimorfismo, es uno de los mecanismos más poderosos que ofrece la


orientación al objeto, para soportar la reutilización del código y la robustez.

El ambiente de programación, proporciona un gran número de clases, las que


pueden ser adaptadas, mediante la herencia, a las necesidades de una aplicación en
particular.
Cambios en el main para ejercicio de la clase padre Punto y clase hija Punto3D
2.212
…..
Punto3D p2 = new Punto3D(0, 0, 0);
Punto p4 = new Punto3D(40, 50, 60);//Cumple la regla de herencia
Punto3D p5 = (Punto3D) p4;
StdOut.println("p2="+p2.getX()+ ", "+p2.getY()+", "+ p2.getZ());
StdOut.println("p4 = " + p4.getX() + ", " + p4.getY());
//No se puede desplegar z en p4
StdOut.println("p5="+p5.getX()+", "+p5.getY()+", "+p5.getZ());
StdOut.println("------------------------------");
En tiempo de compilación se chequea que distancia(Punto3D) esté definido en la clase Punto, ya que la declaración de p4 es
Punto. Esto se cumple, porque en la clase Punto está el método distancia(Punto). Se debe considerar que un objeto de la clase
Punto3D también es un objeto de la clase Punto.
En tiempo de ejecución se ejecuta el segundo método distancia de la clase Punto, distancia(Punto), el cual invoca a
this.distancia(int, int). Este último método está tanto en la clase Punto como en la clase Punto3D, está redefinido en Punto3D. Se
aplica el de la clase Punto3D, porque en tiempo de ejecución p4 es una instancia de Punto3D

StdOut.println("p4.distancia(p2) = "+ p4.distancia(p2));


StdOut.println("------------------------------");
En tiempo de compilación se chequea que distancia(Punto3D) esté definido en la clase Punto3D, ya que p5 es de la clase
Punto3D.
En tiempo de ejecución se ejecuta el segundo método distancia de la clase Punto3D, distancia(Punto3D), el cual invoca a
this.distancia(int, int, int). Este último método corresponde al primer método distancia de la clase Punto3D.

StdOut.println("p5.distancia(p2) = " + p5.distancia(p2));


StdOut.println("------------------------------");

StdOut.println("p5.distancia(1,1,2) = " + p5.distancia(1,1,2));

Se imprime
p2 = 0, 0, 0
p4 = 40, 50
p5 = 40, 50, 60
------------------------------
Segundo metodo distancia del padre (Punto). Parametros: Punto
Tercer metodo distancia del hijo Punto3D. Parametros: x, y
p4.distancia(p2) = 1.0671873729054748
------------------------------
Segundo metodo distancia del hijo Punto3D. Parametros: Punto3D
Primer metodo distancia del hijo Punto3D. Parametros: x, y, z
p5.distancia(p2) = 87.74964387392122
------------------------------
Primer metodo distancia del hijo Punto3D. Parametros: x, y, z
p5.distancia(1,1,2) = 85.3580693314932
------------------------------
2.213
2.9.3. Clase abstracta
Volvamos al ejemplo de las figuras
Figura
Variables de instancia: Clase abstracta
 Centro
 Color
Métodos:
 Ubicar
 Dibujar
Métodos
 Imprimir
abtractos
 Rotar
 Color

Figura
<<abstracta>>

Rectángulo Triángulo Círculo

Rectángulo Triángulo Circulo


Variables de instancia: Variables de instancia: Variables de instancia:
 Vértices  Limites  Radio
Métodos:
Métodos:  Dibujar Métodos:
 Dibujar  Imprimir  Dibujar
 Imprimir  Rotar  Imprimir
 Rotar  Rotar

 La clase Figura debe tener como abstractos los métodos rotar, dibujar e
imprimir. Lo anterior tiene la finalidad de que el chequeo en tiempo de
compilación sea exitoso cuando se invoca un método para un objeto de una de
las subclases de Figura.
 Por lo tanto, cuando se deba crear (new) una figura lo que realmente se hará
es crear un círculo o un triángulo o un rectángulo. De esta forma, cuando se
invoque un método como rotar para un círculo, se ejecute el rotar del círculo.
Lo mismo con los métodos imprimir y dibujar. Esto significa que nuca
haremos new Figura()
2.214

A) Conceptos
 Algunas de las clases tendrán instancias, otras no.
 La clase que no tienen instancias, se denomina clases abstractas.
 Una clase abstracta es escrita con el propósito de que sus subclases le
agreguen estructura y comportamiento, a través de completar la
implementación de sus (usualmente) métodos incompletos.
 No se pueden crear instancias de dichas clases directamente, con el
operador new.

 Si la clase no tiene un método abstracto no necesita


ser abstracta.
 Si la clase tiene un método abstracto y no se declara
como clase abstracta NO COMPILA

Clase abstracta
Es una clase que nunca es instanciada. Contiene los métodos comunes a
todas las subclases.
Es usada como una base, a partir de la cual, otras clases pueden heredar.

Método Abstracto
Es un método cuya implementación no es definida en la declaración de la
clase en que aparece. Su definición se hace en una clase descendente.
2.215
Ejemplo: Se tiene una clase con un método abstracto, seguida de una
clase que implementa ese método.

public abstract class A { //clase abstracta


public abstract void callme(); //método abstracto A
<<abstract>>
public void metoo(){
StdOut.println("Inside A's metoo method"); + abs callme()
} + metoo()
}

public class B extends A {


public void callme(){ B
StdOut.println("Inside B's callme method");
} + callme()
}

public class Abstract {


public static void main(String args[]){
A a = new B();
a.callme(); //Se usa el del hijo, ya que el objeto es una
//instancia de la subclase
a.metoo();
}
}

Resultado
Inside B’s callme method
Inside A’s metoo method
2.216
Modificador final, para calificar una variable, método o clase

Por defecto todos los métodos y las variables de instancia, se pueden


sobrescribir.

En Java, si se desea declarar que ya no se quiere que las subclases


sobrescriban las variables o métodos, esto se puede declarar como final.

 Ejemplo para variables:

final int NUEVOARCHIVO= 1;

Por convención los nombres de los valores constantes están en


mayúscula.

 final asociado a un método, indica que este no puede ser sobrescrito por
las subclases.

 final, usado como modificador de una clase, indica que la clase no puede
tener subclases.

public final class Integer

public final class Math


2.217
Ejemplo

public class App {

public static void main(String[] args) {


//Constantes
final int constante1=1;
//constante1 = 2; NO COMPILA. La constante
constante1 está definida como final
final int CONSTANTE2 = 5;
}
}

public class ClaseA {


protected int a1;
protected int a2;
public ClaseA(int a1, int a2) {
this.a1 = a1;
this.a2 = a2;
}
public int getA1() {
return a1;
}
public void setA1(int a1) {
this.a1 = a1;
}
public int getA2() {
return a2;
}
public void setA2(int a2) {
this.a2 = a2;
}
public final int sumar() {
return a1*a2;
}
}
2.218
public final class ClaseB extends ClaseA{
private int b1;

public ClaseB(int a1, int a2, int b1) {


super(a1, a2);
this.b1 = b1;
}
public int getB1() {
return b1;
}
public void setB1(int b1) {
this.b1 = b1;
}
public int getA1() {
return a1;
}

/*
NO COMPILA. El método sumar está
public int sumar() { declarado como final en la superclase
return a1*a2; ClaseA, superclase de la clase ClaseB
}
*/
}
NO COMPILA. La
public class ClaseC extends ClaseB{
clase ClaseB está
private int c1;
definida como final
public ClaseC(int a1, int a2, int b1, int c1) {
super(a1, a2, b1);
this.c1 = c1;
}
public int getC1() {
return c1;
}
public void setC1(int c1) {
this.c1 = c1;
}
}
2.219
Resumen de los atributos que pueden tener variables y métodos

VARIABLE:

{private / public / protected}

{final}

{static}

MÉTODO:

{private / public / protected}

{final / abstract}

{static}

Sólo se puede especificar uno de los atributos puestos en la misma llave.


2.220
B) Ejemplos
Ejemplo 1: Cuenta bancaria
En un banco se manejan cuentas de ahorro y cuentas corrientes. Estos dos
tipos de cuenta son idénticos, excepto en las siguientes diferencias:
 Las cuentas de ahorro se numeran como 1xxxxx, empezando por 100001.
 Las cuentas corrientes se numeran como 5xxxx, empezando por 500001.
 Las cuentas de ahorro no tienen un cargo mensual (mantención), si el
saldo es superior a $200.000. Si no, se cobran $5.000 por mes. Las
cuentas corrientes pagan una cuota mensual de $5.000
 Las cuentas corrientes no pagan ningún interés, hasta que el saldo supera
los $500.000. A las cuentas de ahorro siempre se les paga interés.
 La aplicación muestra el resultado de ingresar $100.000 al mes, tanto en
una cuenta corriente como en una cuenta de ahorro a una cierta tasa de
interés anual. Esto se hace por 10 meses. Se debe chequear que la tasa de
interés esté entre 0 y 20 %.

Modelo del dominio


Cuenta de ahorro Cuenta corriente
número de cuenta número de cuenta
saldo saldo
tasa de interés tasa de interés

Contratos
Operación depositar (monto depósito) Recuerde que el
chequeo del monto
Descripción Se deposita dinero en la cuenta corriente y del depósito > 0 es
en la cuenta de ahorro
validación del dato de
Precondiciones Que exista la cuenta corriente entrada. Se hace en
Que exista la cuenta de ahorro la App
Postcondiciones Saldo actualizado de la cuenta corriente Por lo tanto no va en
Saldo actualizado de la cuenta de ahorro el contrato
2.221

Operación Descontar mantención ()


Descripción Se descuenta al saldo de las 2 cuentas el valor de la mantención,
según corresponda
Precondiciones Que existan las 2 cuentas bancaria (la corriente y la de ahorro)
Postcondiciones Saldo actualizado de c/u de las cuentas

Operación Agregar interés (tasa de interés)


Descripción Se agrega al saldo de las 2 cuenta el monto asociado a los intereses,
según corresponda
Precondiciones Que existan las 2 cuentas bancaria (la corriente y la de ahorro)

Postcondiciones Saldo actualizado de c/u de las cuentas

Operación Chequear tasa de interés (tasa interés)

Descripción Se chequea que la tasa de interés esté entre 0 y 20


Precondiciones Que la tasa de interés esté entre 0 y 20 Esto es relativo,
ya que podría ser
Postcondiciones
considerado
como validación
de datos y no
Operación Obtener datos cuenta ahorro como una pre
Descripción Se obtienen los datos de la cuenta de ahorro condición

Precondiciones Que exista la cuenta de ahorro


Postcondiciones

Operación Obtener datos cuenta corriente

Descripción Se obtienen los datos de la cuenta corriente


Precondiciones Que exista la cuenta corriente
Postcondiciones
2.222
Diagrama de clases del dominio de la aplicación

CuentaBancaria
- double $ tasaInteres
- int saldo
+ CuentaBancaria(int saldi)
+ $ getTasaInteres(): double
+ $ setTasaInteres(double tasaInteres)
+ depositar(int montoDeposito)
+ girar(int montoGiro): boolean
+ getSaldo(): int
+ setSaldo(int saldo)
+ toString(): String

CuentaCorriente CuentaAhorro
- int $ corrNumero - int $ corrNumero
- int numeroCuenta - int numeroCuenta
+ CuentaCorriente(int saldo) + CuentaAhorro(int saldo)
+ get y set NumeroCuenta()… + get y set NumeroCuenta()…
+ $ getCorrNumero(): int + $ getCorrNumero(): int
+ $ setCorrNumero(int corrNumero) + $ setCorrNumero(int corrNumero)
+ agregarInteres() + descontarMantencion()
+ toString(): String + toString(): String

La responsabilidad de agregar La responsabilidad de


intereses si corresponde es de descontar la mantención si
la cuenta corriente corresponde es de la cuenta de
ahorro
2.223
Diagrama de clases CuentaBancaria
- double $ tasaInteres
- int saldo
+ CuentaBancaria(int saldo)
+ $ getTasaInteres(): double
+ $ setTasaInteres(double tasaInteres)
+ depositar(int montoDeposito)
+ girar(int montoGiro): boolean
+ getSaldo(): int
+ setSaldo(int saldo)
+ toString(): String

CuentaCorriente CuentaAhorro
- int $ corrNumero - int $ corrNumero
- int numeroCuenta - int numeroCuenta
+ CuentaCorriente(int saldo) + CuentaAhorro(int saldo)
+ get y set NumeroCuenta()… + get y set NumeroCuenta()…
+ $ getCorrNumero(): int + $ getCorrNumero(): int
+ $ setCorrNumero(int corrNumero) + $ setCorrNumero(int corrNumero)
+ agregarInteres() + descontarMantencion()
+ toString(): String + toString(): String

1 1

SistemaCuentaCorrienteCuentaAhorroImpl
- CuentaCorriente cuentaCorriente
- CuentaAhoro cuentaAhorro

<<implements>>

SistemaCuentaCorrienteCuentaAhorro
<<interface>>
+ chequearTasaInteres(tasaInteres)
+ obtenerDatosCuentaCorriente(): String
+ obtenerDatosCuentaAhorro(): String
+ depositar(monto)
+ descontarMantencion()
+ agregarInteres(tasaInteres)
2.224

package cl.ucn.ei.pa.sistemacuentaahorrocuentacorriente.dominio;

public class CuentaBancaria {


private double saldo;
private static double tasaInteres;

public CuentaBancaria(double saldo) {


this.saldo = saldo;
}

public double getSaldo() {


return saldo;
}

public void setSaldo(double saldo) {


this.saldo = saldo;
}

public static double getTasaInteres() {


return tasaInteres;
}

public static void setTasaInteres(double tasaInteres) {


CuentaBancaria.tasaInteres = tasaInteres;
}

public void depositar(double montoDeposito){


saldo = saldo + montoDeposito;
}
2.225

public boolean girar(double montoGiro){


if (montoGiro < saldo){
saldo = saldo - montoGiro;
return true;
}
else{
return false;
}
}

@Override
public String toString() {
return "CuentaBancaria [saldo=" + saldo + "]";
}
}

package cl.ucn.ei.pa.sistemacuentaahorrocuentacorriente.dominio;

public class CuentaAhorro extends CuentaBancaria{


private int numeroCuenta ;
private static int correlativoNumeroCuenta = 100001;

public CuentaAhorro(int saldo) {


super(saldo);
numeroCuenta = correlativoNumeroCuenta;
//numeroCuenta = correlativoNumeroCuenta++;
correlativoNumeroCuenta++;
}

public int getNumeroCuenta() {


return numeroCuenta;
}

public void setNumeroCuenta(int numeroCuenta) {


this.numeroCuenta = numeroCuenta;
}
2.226

public static int getCorrelativoNumeroCuenta() {


return correlativoNumeroCuenta;
}

public static void setCorrelativoNumeroCuenta(


int correlativoNumeroCuenta) {
CuentaAhorro.correlativoNumeroCuenta=correlativoNumeroCuenta;
}

public void decontarMantencion() {


if(this.getSaldo() <= 200){
this.girar(5);
}
}

@Override
public String toString() {
return "CuentaAhorro [numeroCuenta=" + numeroCuenta +
", saldo=" + getSaldo() + "]";
}
}

package cl.ucn.ei.pa.sistemacuentaahorrocuentacorriente.dominio;

public class CuentaCorriente extends CuentaBancaria{


private int numeroCuenta ;
private static int correlativoNumeroCuenta = 500001;

public CuentaCorriente(int saldo) {


super(saldo);
numeroCuenta = correlativoNumeroCuenta;
//numeroCuenta = correlativoNumeroCuenta++;
correlativoNumeroCuenta++;
}

public int getNumeroCuenta() {


return numeroCuenta;
}

public void setNumeroCuenta(int numeroCuenta) {


this.numeroCuenta = numeroCuenta;
}
2.227

public static int getCorrelativoNumeroCuenta() {


return correlativoNumeroCuenta;
}

public static void setCorrelativoNumeroCuenta(


int correlativoNumeroCuenta) {
CuentaCorriente.correlativoNumeroCuenta =
correlativoNumeroCuenta;
}

public void agregarInteres() {


if(this.getSaldo() >= 500000){
this.depositar((CuentaBancaria.getTasaInteres()/12)
* this.getSaldo());
}
}

@Override
public String toString() {
return "CuentaCorriente [numeroCuenta=" + numeroCuenta +
", saldo= "+ getSaldo()+"]" ;
}
}

package cl.ucn.ei.pa.sistemacuentaahorrocuentacorriente.logica;

public interface SistemaCuentaCorrienteCuentaAhorro {

public void chequearTasaInteres(double tasaInteres);


public String obtenerDatosCuentaCorriente();
public String obtenerDatosCuentaAhorro() ;
public void depositar(int monto);
public void descontarMantencion();
public void agregarInteres();

}
2.228

package cl.ucn.ei.pa.sistemacuentaahorrocuentacorriente.logica;

import cl.ucn.ei.pa.sistemacuentaahorrocuentacorriente.dominio.*;

public class SistemaCuentaCorrienteCuentaAhorroImpl implements


SistemaCuentaCorrienteCuentaAhorro{

private CuentaCorriente cuentaCorriente;


private CuentaAhorro cuentaAhorro;

public SistemaCuentaCorrienteCuentaAhorroImpl(){
//Cuando se levanta el sistema, se crean las
//2 cuentas con un saldo 0
cuentaAhorro = new CuentaAhorro(0);
cuentaCorriente = new CuentaCorriente(0);
}

public void chequearTasaInteres(double tasaInteres){


if (tasaInteres >=0.0 && tasaInteres <= 20.0){
CuentaBancaria.setTasaInteres(tasaInteres);
}
else{
throw new IllegalArgumentException(
"Tasa interes fuera de rango");
}
}

public String obtenerDatosCuentaCorriente(){


return cuentaCorriente.toString();
}

public String obtenerDatosCuentaAhorro() {


return cuentaAhorro.toString();
}
2.229
public void depositar(int monto){
if (cuentaCorriente != null && cuentaAhorro!= null ){
cuentaAhorro.depositar(monto);
cuentaCorriente.depositar(monto);
}
else{
throw new NullPointerException ("Cuenta no existe");
}
}

public void descontarMantencion(){


if (cuentaCorriente != null && cuentaAhorro!= null ){
cuentaCorriente.girar(5);
cuentaAhorro.descontarMantencion();
}
else{
throw new NullPointerException ("Cuenta no existe");
}
}

public void agregarInteres(){


if (cuentaCorriente != null && cuentaAhorro!= null ){
cuentaCorriente.agregarInteres();
cuentaAhorro.depositar((CuentaBancaria.getTasaInteres()/12) *
cuentaAhorro.getSaldo());
}
else{
throw new NullPointerException ("Cuenta no existe");
}
}
}
2.230

package cl.ucn.ei.pa.sistemacuentaahorrocuentacorriente.logica;

import ucn.StdIn;
import ucn.StdOut;

public class App {

public static void main(String[] args) {

SistemaCuentaCorrienteCuentaAhorro sistema =
new SistemaCuentaCorrienteCuentaAhorroImpl();

StdOut.print("Ingrese tasa de interes: ");


double tasaInteres = StdIn.readDouble();
try{
sistema.chequearTasaInteres(tasaInteres);
}catch(IllegalArgumentException ex){
StdOut.println(ex.getMessage());
}

try{
StdOut.println("datos cuenta corriente: + " +
sistema.obtenerDatosCuentaCorriente());
}catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}

StdOut.println();

try{
StdOut.println("datos cuenta ahorro: + " +
sistema.obtenerDatosCuentaAhorro());
}catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}

StdOut.println();
2.231

//10 depositos de 100 c/u en las cuentas


for(int i = 1; i <= 10; i++){
try{
sistema.depositar(100);
sistema.descontarMantencion();
sistema.agregarInteres();

StdOut.println("datos cuenta corriente: + " +


sistema.obtenerDatosCuentaCorriente());
StdOut.println();
StdOut.println("datos cuenta ahorro: + " +
sistema.obtenerDatosCuentaAhorro());
StdOut.println();
}catch(NullPointerException ex1){
StdOut.println(ex1.getMessage());
}
}
}

}
2.232
Concepto de Casteo A
- int a1
+ A(int a1)
+ m1()

B C
- int b1 - int c1
+ A(int a1, int b1) + A(int a1, int c1)
+ m2() + m3()

Un objeto de la clase B también es objeto de la clase A


A o1 = new B(2,3); //Cumple con la regla de herencia

¿De qué perspectiva o punto de vista quiero ver a o1?


 Puedo verlo desde la perspectiva de A
Se puede realizar:
o1.m1()
a1 b1
o1.a1 A o1 2 3

 Puedo verlo desde la perpectiva de B


B b
B b = (B) o1; casteo
Se puede realizar:
b.m1()
b.m2()
b.a1
b.b1
2.233
Ejemplo 2: Vehículos
Construir un programa que maneje información de vehículos. Un vehículo
tiene un número de patente, marca y año de fabricación.

Entre los vehículos es posible distinguir los autos y las camionetas. Para los
autos se tiene además, la lectura del cuenta kilómetros y la capacidad del
estanque de combustible. Para las camionetas se tiene además, su capacidad
de carga.

La siguiente funcionalidad, mediante un menú, debe estar disponible para el


usuario del programa:

 Ingresar información de una cantidad indeterminada de autos y


camionetas (no se conoce la secuencia en que viene los datos; sí primero
un auto, luego un auto, luego una camioneta, etc.; la secuencia es
cualquiera)
 Listado de cada uno de los vehículos con sus datos asociados, en la
misma secuencia en que fueron ingresados.
 Dada la patente de un vehículo, se piden los datos de ese vehículo.
Además se pide el costo asociado por reparación. Si es camioneta el costo
es $100.000 por unidad de capacidad. Si es auto, es $20.000 por capacidad
del estanque.
 Cantidad total de vehículos, cantidad total de autos, cantidad total de
camionetas.
 Datos de la camioneta con la mayor capacidad de carga.

Se pide:
 Modelo del dominio
 Contratos
 Diagrama de clases del dominio de la aplicación
 Diagrama de clases
 Código Java
2.234
Modelo del dominio
Auto Camioneta
 Patente  Patente
 Marca  Marca
 Año
 Año
 Lectura cuenta kilómetros
 Capacidad estanque combustible  Capacidad de carga

Contratos
Operación Ingresar camioneta (patente, marca, año, capacidad carga)
Descripción Se ingresa una camioneta a la lista general de vehículos
Precondiciones
Postcondiciones Camioneta ingresada a la lista general de vehículos
10

Operación Ingresar auto (patente, marca, año, kilómetros, capacidad


estanque)
Descripción Se ingresa un auto a la lista general de vehículos
Precondiciones
Postcondiciones Auto ingresado a la lista general de vehículos

Operación Obtener datos de todos los vehículos


Descripción Se obtienen los datos de todos los vehículos
Precondiciones
Postcondiciones
2.235

Operación Obtener datos de un vehículo, incluyendo su costo de


reparación (patente)
Descripción Se obtiene los datos del vehículo
Precondiciones Que exista el vehículo
Postcondiciones

Operación Obtener total de autos

Descripción Se obtiene la cantidad total de autos


Precondiciones
Postcondiciones

Operación Obtener total de camionetas


Descripción Se obtiene la cantidad total de camionetas
Precondiciones
Postcondiciones

Operación Obtener total de vehículos


Descripción Se obtiene la cantidad total de vehículos
Precondiciones
Postcondiciones
2.236

Operación Obtener datos de la camioneta con mayor capacidad de


carga
Descripción Se obtienen los datos de la camioneta con la mayor capacidad
de carga
Precondiciones
Postcondiciones

Diagrama de clases del dominio de la aplicación


ListaVehiculos * Vehículo
<< abstract>>
- Vehiculo [ ] lv - String patente
- int cantidadVehiculos - String marca
- int max - int agno
+ ListaVehiculos(int max)
+ ingresarVehiculo(Vehiculo vehiculo): # Vehiculo(String patente,
boolean String marca, int agno)
+ getCantidadVehiculos(): int + getMarca(): String
+ getVehiculoI(int i): Vehiculo + getAgno (): int
+ buscarVehiculo(String patente): + getPatente(): String
Vehiculo + abs costoReparacion(): int
+ toString(): String + toString(): String

Camioneta Auto
- int capacidadCarga - int kilometraje
+ Camioneta(String patente,
- int capacidadEstanque
+ Auto(String patente, String marca,
String marca, int agno, int agno, int kilomeraje,
int capacidadCarga) int capacidadEstanque)
+get y set ... + get y set ….
+ costoReparacion(): int + costoReparacion(): int
+ toString(): String + toString(): String

Recuerde que si una clase tiene un método


abstracto, tiene que ser abstracta. De hecho, sino
la define como abstracta arroja un error de
compilación
2.237
Diagrama de clases
Vehículo
ListaVehiculos * << abstract>>
- Vehiculo [ ] lv - String patente
- int cantidadVehiculos - String marca
- int max - int agno
# Vehiculo(String patente,
+ ListaVehiculos(int max)
String marca, int agno)
+ ingresarVehiculo(Vehiculo vehiculo):
+ getMarca(): String
boolean
+ getAgno (): int
+ getCantidadVehiculos(): int
+ getPatente(): String
+ getVehiculoI(int i): Vehiculo
+ abs costoReparacion(): int
+ buscarVehiculo(String patente):
+ toString(): String
Vehiculo
+ toString(): String

1 Camioneta Auto
- int capacidadCarga - int kilometraje
+ Camioneta(String patente,
- int capacidadEstanque
+ Auto(String patente, String marca,
String marca, int agno, int agno, int kilomeraje,
int capacidadCarga) int capacidadEstanque)
+get y set ... + get y set ….
+ costoReparacion(): int + costoReparacion(): int
+ toString(): String + toString(): String

SistemaVehiculos
<<interface>>
+ingresarAuto(): boolean
+ingresarCamioneta(): boolean
+obtenerDatosVehiculos(): String
+obtenerDatosVehiculo (): String
+obtenerTotalAutos(): int
+obtenerTotalCamionetas(): int
+obtenerTotalVehiculos(): int
+obtenerDatosCamionetaMasCarga(): String

<<implements>>
SistemaVehiculosImpl
ListaVehiculos listaVehiculos
2.238
package cl.ucn.ei.pa.sistemavehiculos.dominio;

public abstract class Vehiculo {


private String patente;
private String marca;
private int agno;

protected Vehiculo(String patente , String marca,


int agno) {
this.patente = patente;
this.marca = marca;
this.agno = agno;
}
public String getPatente() {
return (patente);
}
public String getMarca() {
return marca;
}
public int getAgno () {
return agno;
}
abstract public int costoReparacion();
//Método abstracto

@Override
public String toString() {
return "Vehiculo [" + (patente != null ?
"patente=" + patente + ", " : "")+
(marca != null ? "marca=" + marca + ", " : "")+
"agno=" + agno + "]";
}
}
2.239

package cl.ucn.ei.pa.sistemavehiculos.dominio;
public class Auto extends Vehiculo{
private int kilometraje;
private int capacidadEstanque;
public Auto(String patente, String marca, int agno,
int kilometraje, int capacidadEstanque) {
super(patente , marca , agno);
this.capacidadEstanque = capacidadEstanque;
this.kilometraje=kilometraje;
}
public int getKilometraje() {
return kilometraje;
}
public int getCapacidadEstanque() {
return capacidadEstanque;
}
public int costoReparacion () {
return (capacidadEstanque * 20000);
}
@Override
public String toString() {
return "patente: "+ getPatente() + " marca: "+
getMarca()+ " agno: " + getAgno()+ " " +
"Auto [kilometraje=" + kilometraje +
", capacidadEstanque=" + capacidadEstanque + "]";
}
}
2.240

package cl.ucn.ei.pa.sistemavehiculos.dominio;
public class Camioneta extends Vehiculo{
private int capacidadCarga;
public Camioneta (String patente, String marca,
int agno, int capacidadCarga) {
super(patente, marca, agno);
this.capacidadCarga = capacidadCarga;
}

public int getCapacidadCarga() {


return capacidadCarga;
}

public int costoReparacion () {


return (capacidadCarga * 100000);
}

@Override
public String toString() {
return "patente: "+ getPatente() + " marca: "+
getMarca()+ " agno: " + getAgno()+ " Camioneta
[capacidadCarga=" + capacidadCarga + "]";
}

}
2.241

package cl.ucn.ei.pa.sistemavehiculos.logica;
import cl.ucn.ei.pa.sistemavehiculos.dominio.Auto;
import cl.ucn.ei.pa.sistemavehiculos.dominio.Camioneta;
import cl.ucn.ei.pa.sistemavehiculos.dominio.Vehiculo;
public class ListaVehiculos {
private Vehiculo[ ] lv;
private int cantidadVehiculos;
int max;
public ListaVehiculos(int max) {
lv = new Vehiculo [max];
cantidadVehiculos =0;
this.max = max;
}
public int getCantidadVehiculos() {
return cantidadVehiculos;
}
public Vehiculo getVehiculoI (int i) {
if (i >= 0 && i < cantidadVehiculos){
return lv[i];
}
return null;
}

//Ingresa un vehículo a la lista


public boolean ingresarVehiculo(Vehiculo v) {
if (cantidadVehiculos < max){
lv[cantidadVehiculos]= v;
cantidadVehiculos++;
return true;
}
else{
return false;
}
}
2.242

//Busca una patente de un vehículo en la lista


public Vehiculo buscarVehiculo(String patente) {
int j=0;
while (j < cantidadVehiculos &&
!lv[j].getPatente().equals(patente)){
j++;
}
if (j == cantidadVehiculos){
return null;
}
else{
return lv[j];
}
}

@Override
public String toString() {
String salida = "";
for(int i = 0; i < cantidadVehiculos; i++){
Vehiculo vehiculo = getVehiculoI(i);

if (vehiculo instanceof Camioneta) {


Camioneta camioneta = (Camioneta) vehiculo;
salida = salida + camioneta.toString();
}
else {
Auto auto = (Auto) vehiculo;
salida = salida + auto.toString();
}
salida = salida + " costo reparacion" +
vehiculo.costoReparacion()+ "\n";
}
return salida;
}
}
2.243

package cl.ucn.ei.pa.sistemavehiculos.logica;
import cl.ucn.ei.pa.sistemavehiculos.dominio.*;

public interface SistemaVehiculos {

public boolean ingresarAuto (String patente,


String marca, int año, int kilometros,
int capacidadEstanque);

public boolean ingresarCamioneta(String patente,


String marca,int año, int capacidadCarga);

public String obtenerDatosVehiculos();

public String obtenerDatosVehiculo (String patente);

public int obtenerTotalAutos();

public int obtenerTotalCamionetas();

public int obtenerTotalVehiculos();

public String obtenerDatosCamionetaMasCarga();

}
2.244

package cl.ucn.ei.pa.sistemavehiculos.logica;

import cl.ucn.ei.pa.sistemavehiculos.dominio.*;

public class SistemaVehiculosImpl implements


SistemaVehiculos{
private ListaVehiculos listaVehiculos;

public SistemaVehiculosImpl(){
listaVehiculos = new ListaVehiculos(10);
}

public boolean ingresarAuto(String patente, String marca,


int agno, int kilometros, int capacidadEstanque){

Vehiculo auto = new Auto (patente, marca, agno,


kilometros, capacidadEstanque);
boolean ingreso =
listaVehiculos.ingresarVehiculo(auto);
return ingreso;
}

public boolean ingresarCamioneta (String patente,


String marca, int año, int capacidadCarga){

Vehiculo camioneta = new Camioneta(patente, marca,


año, capacidadCarga);
boolean ingreso =
listaVehiculos.ingresarVehiculo(camioneta);

return ingreso;
}
2.245

public String obtenerDatosVehiculos(){


if (listaVehiculos!= null){
return listaVehiculos.toString();
}
else{
return null;
}
}

public String obtenerDatosVehiculo (String patente){


Vehiculo vehiculo =
listaVehiculos.buscarVehiculo(patente);
if (vehiculo !=null){
if (vehiculo instanceof Auto){
Auto auto = (Auto) vehiculo;
return auto.toString()+"costo reparacion: "
+ auto.costoReparacion();
}
else{
Camioneta camioneta=(Camioneta) vehiculo;
return camioneta.toString()+
"costo reparacion: " +
camioneta.costoReparacion();
}
}
throw new NullPointerException(
"No existe vehiculo");
}
2.246

public int obtenerTotalAutos(){


int cantidadAutos = 0;

for(int i=0;
i<listaVehiculos.getCantidadVehiculos();i++){

Vehiculo vehiculo =
listaVehiculos.getVehiculoI(i);

if (vehiculo instanceof Auto){


cantidadAutos++;
}
}
return cantidadAutos;
}

public int obtenerTotalCamionetas(){


int cantidadCamionetas = 0;
for(int i=0;
i< listaVehiculos.getCantidadVehiculos();i++){
Vehiculo vehiculo =
listaVehiculos.getVehiculoI(i);
if (vehiculo instanceof Camioneta){
cantidadCamionetas++;
}
}
return cantidadCamionetas;
}

public int obtenerTotalVehiculos(){


return listaVehiculos.getCantidadVehiculos();
//return (listaVehiculos.obtenerTotalCamionetas +
//listaVehiculos.obtenerTotalAutos);
}
2.247

public String obtenerDatosCamionetaMasCarga(){


int mayor= -1;
Camioneta camionetaMasCarga= null;
for(int i = 0;
i<listaVehiculos.getCantidadVehiculos();i++){

Vehiculo vehiculo =
listaVehiculos.getVehiculoI(i);
if (vehiculo instanceof Camioneta){
Camioneta camioneta = (Camioneta) vehiculo;
if (camioneta.getCapacidadCarga()> mayor){
mayor = camioneta.getCapacidadCarga();
camionetaMasCarga = camioneta;
}
}
}
if(camionetaMasCarga != null){
return camionetaMasCarga.toString();
}
else{
return null;
}
}
}
2.248

package cl.ucn.ei.pa.sistemavehiculos.logica;

import cl.ucn.ei.pa.sistemavehiculos.dominio.*;
import ucn.StdIn;
import ucn.StdOut;

public class App {

public static void leerUnVehiculo (SistemaVehiculos


sistema){
//Ingresa datos de un vehiculo
String patente,marca;
int kilometraje,capacidadEstanque,agno,tipo;
StdOut.print("Tipo vehiculo Auto[1] Camioneta[2]");
tipo = StdIn. readInt();
if (tipo == 1) {
StdOut.print("Ingrese patente = ");
patente = StdIn.readString();
StdOut.print("Ingrese la marca = ");
marca = StdIn.readString();
StdOut.print("Ingrese agno fabricacion = ");
agno = StdIn.readInt();
StdOut.print("Ingrese el kilometraje=");
kilometraje = StdIn.readInt();
StdOut.print("Ingrese capacidad estanque = ");
capacidadEstanque = StdIn.readInt();
boolean ingreso =
sistema.ingresarAuto(patente, marca, agno,
kilometraje, capacidadEstanque);
if(!ingreso){
StdOut.println("No se hizo el ingreso del
auto. No hay espacio");
}
}
2.249

else {
if (tipo == 2) {
StdOut.print("Ingrese patente = ");
patente = StdIn.readString();
StdOut.print("Ingrese la marca =");
marca = StdIn.readString();
StdOut.print("Ingrese agno fabricacion= ");
agno = StdIn.readInt();
StdOut.print("Ingrese capacidad carga = ");
int capacidadCarga = StdIn.readInt();
boolean ingreso =
sistema.ingresarCamioneta(patente,
marca, agno, capacidadCarga);
if(!ingreso){
StdOut.println("No se hizo el ingreso
de la camioneta. No hay espacio");
}
}
}
}

public static void desplegarMenu(){


StdOut.println(" ");
StdOut.println(" M E N U");
StdOut.println("[1] Ingresar vehiculo ");
StdOut.println("[2] Listado de vehiculos ");
StdOut.println("[3] Buscar patente y desplegar
costo de reparacion");
StdOut.println("[4] Cantidad de vehiculos (autos
y camionetas) ");
StdOut.println("[5] Datos de la camioneta con la
mayor capacidad de carga ");
StdOut.println("[6] Salir ");
}
2.250
public static void menu(SistemaVehiculos sistema){
desplegarMenu();
StdOut.print("Ingrese opcion:");
int opcion = StdIn.readInt();
while(opcion != 6){
switch(opcion) {

case 1:
leerUnVehiculo (sistema);
break;

case 2:
StdOut.println(" ");
StdOut.println(sistema.
obtenerDatosVehiculos());

break;

case 3:
StdOut.print("Patente a buscar: ") ;
String patente = StdIn.readString();
try{
StdOut.println(" ");
StdOut.println(sistema.
obtenerDatosVehiculo(patente));
}catch (NullPointerException ex) {
StdOut.println(ex.getMessage());
}

break;
2.251

case 4: int totalVehiculos =


sistema.obtenerTotalVehiculos();
StdOut.println("Total de vehiculos: " +
totalVehiculos);
int totalAutos= sistema.obtenerTotalAutos();
StdOut.println("Total autos: " + totalAutos);
int totalCamionetas =
sistema.obtenerTotalCamionetas();
StdOut.println("Total camionetas: " +
totalCamionetas);
break;
case 5:
//Muestra los datos de la camioneta con la
//mayor capacidad de carga

String datosCamioneta = sistema.


obtenerDatosCamionetaMasCarga()
if (datosCamioneta!= null) {
StdOut.println(datosCamioneta);
}
}
break;

} //fin switch
desplegarMenu();
StdOut.print("Ingrese opcion:");
opcion = StdIn.readInt();
}
}

public static void main(String[] args) {


SistemaVehiculos sistema =
new SistemaVehiculosImpl();
menu(sistema);
}
}
2.252
Retomemos el concepto de casteo
Vehículo
Suponga la siguiente instrucción - String patente
- String marca
Java: - int agno
Vehiculo v = new Camioneta() # Vehículo(String patente,
String marca, int agno)
: Camioneta + m1()
+ m2()

m1()
v m2() c
m3()
Auto
Camioneta - int kilometraje
-int capacidadCarga - int capacidadEstanque
+ Camioneta(String patente,
+ Auto(String patente, String marca,
String marca, int agno,
int agno, int kilomeraje,
int capacidadCarga)
int capacidadEstanque)
+ m3() + m4()
v1
¿Desde qué punto de vista quiero ver al objeto: como camioneta o como
vehículo?
 Si se ve como vehículo, sólo puedo ver los métodos m1 y m2.
Se puede achicar la interface del objeto (Vehiculo tiene menos cosas que
camioneta)
Vehiculo v1 = c
Vehiculo v1 = (Vehiculo) c;
 Si se ve como camioneta, se deben ver los métodos m1, m2 y m3.
No se puede agrandar la interface del objeto (Camioneta tiene más cosas
que Vehiculo)
Camioneta c = v
Si el vehículo v no es camioneta si
Por lo tanto: Camioneta c = (Camioneta) v compila, pero lanza una excepción
2.253
Ejemplo 3
Se tiene información de los funcionarios de la empresa de computación
Mandiosoft Ltda. en la cual se encuentra la información de cada uno de los 3
tipos de funcionarios del área de desarrollo de sistemas. Estos pueden ser
Programadores, Analistas o Ingenieros.
Todos los funcionarios tienen información en común, como lo es rut,
nombre, dirección, sueldo base y el tipo de funcionario. Además si es
programador interesa el lenguaje de programación que domina (sólo uno por
programador), las horas extras y el nivel de programador (4: experto, 3:
avanzado, 2: intermedio, 1: rookie). De los analistas además interesa saber
los años de experiencia y finalmente de los ingenieros interesa el título y la
cantidad de cargas familiares.
La empresa Mandiosoft desarrolla proyectos para otras empresas, en cada
uno de estos proyectos participa siempre 1 analista, 1 programador y 1
ingeniero. De cada proyecto interesa el nombre, el código, la duración en
meses y su costo total.
Los datos se leen de la siguiente manera:
 Se tiene un archivo con los datos de todos los proyectos.
 Se tiene un archivo con los datos de todos los funcionarios, donde en cada
registro viene la información de un analista o de un ingeniero o de un
programador. Cada registro debe indicar cuál de ellos es.
 Se tiene un archivo con la asignación de los trabajadores a los proyectos.
Por cada registrio viene el código del proyecto y el rut del funcionario
2.254
Requerimientos
Una vez ingresada la información, se necesita:
 Listado de Proyectos con los costos involucrados (por meses y total)
 Listado de funcionarios con sus respectivos sueldos. No es necesario
desplegar los proyectos en los que participa.
 Dado un proyecto entregar el listado de gente involucrada.
 Dado un funcionario entregar el listado de proyectos en que participa.
 Para cada funcionario ingeniero, su nombre y su título.
Los sueldos se calculan de la sigte forma, para el programador además de su
sueldo base, cada hora extra realizada cuesta $5000 además de un bono extra
de $30000 por nivel y otro bono de 20% del valor total mensual del proyecto
por cada proyecto en el que participa. En el caso del analista su sueldo se
calcula con el sueldo base más un bono de $5000 por cada año de
experiencia más el 25% del valor total mensual del proyecto por cada
proyecto en el que participa. Finalmente el ingeniero recibe un sueldo base,
más $8000 por cada carga familiar más un 30% del valor total mensual del
proyecto por cada proyecto en el que participa.
Suponga que cada funcionario trabaja a lo más en 5 proyectos.
2.255
Modelo del dominio
trabaja

Programador 1 1..5 Proyecto


 Rut  Nombre
1..5
 Nombre  Código
 Dirección  Duración en meses
 Sueldo base trabaja  Costo total
 Lenguaje de programación
 Horas extra 1..5
 Nivel de programador
1
Analista trabaja
 Rut
 Nombre
 Dirección
1
 Sueldo base
 Años de experiencia Ingeniero
 Rut
 Nombre
 Dirección
 Sueldo base
 Título
 Cantidad cargas familiares
2.256
Diagrama de clases del dominio de la aplicación
Funcionario
<<abstracta>>
- String rut ListaFuncionarios
- String nombre - Funcionario [] lf
- String direccion * - int cantidadFuncionarios
- int sueldoBase - int max
- ListaProyectos listaProyectos + ListaFuncionarios(int max)
# Funcionario(String rut, String nombre, + ingresar(Funcionario funcionario): boolean
String dirección, int sueldo) + buscar(String rut): funcionario
# abs calcularSueldo(): int + getCantidadFuncionarios(): int
+ getListadoProyectos(): ListaProyectos + getFuncionarioI(int i): Funcionario
+ get y set…()
+ agregarProyecto(Proyecto proyecto) La responsabilidad de agregar un proyecto al funcionario es del funcionario

Programador Analista
- String lenguaje
- int horasExtras
- int anosExperiencia Ingeniero
- int nivel
- int $ porcentajePorProyecto=25 - String titulo
+ Analista(String rut, String nombre,
- int $ porcentajePorProyecto=20 - int cantidadCargas
+ Programador(String rut, String nombre,
String dirección, int sueldo,
int añosExperiencia) - int $ porcentajePorProyecto=30
String dirección, int sueldo,
String lenguaje, int horasExtras, int nivel) + calcularSueldo(): int + Ingeniero(String rut, String nombre,
+ calcularSueldo(): int + get y set… String dirección, int sueldo,
+ get y set …. int titulo, int cantidadCargas)
1 + calcularSueldo(): int
Proyecto 1 + get y set…
- int codigo
- int meses 1
- String nombre 1
- int monto
- Funcionario ingeniero ListaProyectos
- Funcionario analista - Proyecto[] lp
- Funcionario programador - int cantidadProyectos
+ Proyecto(String codigo,String nombre, * - int max
int monto,int meses)
+ getCodigo(): int + ListaProyectos(int max)
+ getNombre(): String + ingresar(Proyecto proyecto):
+ getMonto(): int boolean
+ getMeses(): int + buscar(int codigo): Proyecto
+ setIngeniero(Funcionario ingeniero) + getCantidadProyectos(): int
+ setAnalista(Funcionario analista)
+setProgramador(Funcionario programador)
+ getProyectoI(int i): Proyecto
+ getIngeniero(): Funcionario
+ getAnalista(): Funcionario
+ getProgramador(): Funcionario
2.257
Contratos

Operación Ingresar proyecto (codigo, nombre, monto, meses)


Descripción Se ingresa un proyecto a la lista general de proyectos
Precondiciones
Postcondiciones Proyecto ingresado en la lista general de proyectos

Operación Ingresar analista (rut, nombre, dirección, sueldo base, años


experiencia)
Descripción Se ingresa un analista a la lista general de funcionarios
Precondiciones
Postcondiciones Analista ingresado a la lista general de funcionarios

Operación Ingresar programador (rut, nombre, dirección, sueldo base,


lenguaje programacion, horas extra, nivel programador)
Descripción Se ingresa un programador a la lista general de funcionarios
Precondiciones
Postcondiciones Programador ingresado a la lista general de funcionarios

Operación Ingresar ingeniero (rut, nombre, dirección, titulo, cargas)


Descripción Se ingresa un ingeniero a la lista general de funcionarios
Precondiciones
Postcondiciones Ingeniero ingresado a la lista general de funcionarios
2.258

Operación AsociarFuncionarioProyecto (codigo proyecto, rut)


Descripción Se asocia un funcionario al proyecto:
 El proyecto queda como parte de la lista de proyectos del
funcionario
 El proyecto queda asociado con el funcionario
Precondiciones  Que exista el proyecto
 Que exista el funcionario
Postcondiciones Proyecto con funcionario asociados

Operación Obtener datos de los proyectos


Descripción Se obtienen todos datos de los proyectos, incluido por cada
uno de ellos el costo total y mensual
Precondiciones
Postcondiciones

Operación Obtener datos de los funcionarios


Descripción Se obtienen todos los datos de los funcionarios, incluído el
sueldo
Precondiciones
Postcondiciones

Operación Obtener datos de los funcionario de un proyecto (código


proyecto)
Descripción Se obtienen los datos de los funcionarios asociados a un
proyecto
Precondiciones Que exista el proyecto
Postcondiciones
2.259

Operación Obtener datos proyectos de un funcionario (rut)


Descripción Se obtienen los datos de los proyectos asociados a un
funcionario
Precondiciones Que exista el funcionario
Postcondiciones

Operación Obtener datos de los ingenieros


Descripción Se obtienen los datos de los ingenieros
Precondiciones
Postcondiciones
2.260
Diagrama de clases
ListaFuncionarios ….. ListaProyectos
…. ….

1 1

SistemaProyectosFuncionariosImpl
- ListaProyectos listaProyectos
- ListaFuncionarios listaFuncionarios

<<implements>>

SistemaProyectosFuncionarios
<<interface>>
+ ingresarAnalista(rut, nombre, direccion, sueldoBase, agnosExperiencia): boolean
+ ingresarProgramador(rut, nombre, direccion, sueldoBase, lenguajeProgramacion,
horasExtra, nivelProgramador): boolean
+ ingresarIngeniero(rut,nombre,direccion,sueldoBase,titulo,cantidadCargas):boolean
+ ingresarProyecto(codigo, nombre, monto, meses): boolean
+ asociarFuncionarioProyecto ( codigoProyecto, rut);
+ obtenerDatosProyectos(): String
+ obtenerDatosFuncionarios(): String
+ obtenerDatosFuncionariosProyecto(): String
+ obtenerDatosProyectosFuncionario(rut):String
+ obtenerDatosIngenieros(): String
2.261

package cl.ucn.ei.pa.sistemaFuncionariosProyectos.dominio;

import cl.ucn.ei.pa.sistemaFuncionariosProyectos.logica.ListaProyectos;

public abstract class Funcionario { No vamos a usar el


private String rut; método toString() para
private String nombre;
private String direccion; ninguna de las clases
private int sueldoBase;
private ListaProyectos listaProyectos;

protected Funcionario(String rut, String nombre, String direccion,


int sueldo){
this.rut = rut;
this.nombre = nombre;
this.direccion = direccion;
this.sueldoBase = sueldo;
listaProyectos = new ListaProyectos(5);
}

public String getRut() {


return rut;
}
public void setRut(String rut) {
this.rut = rut;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getDireccion() {
return direccion;
}
public void setDireccion(String direccion) {
this.direccion = direccion;
}
public int getSueldoBase() {
return sueldoBase;
}
2.262

public void setSueldoBase(int sueldoBase) {


this.sueldoBase = sueldoBase;
}
public int getTipo() {
return tipo;
}
public void setTipo(int tipo) {
this.tipo = tipo;
}

public ListaProyectos getListaProyectos() {


return listaProyectos;
}
public void setListaProyectos(ListaProyectos listaProyectos) {
this.listaProyectos = listaProyectos;
}
public int agregarProyecto(Proyecto proyecto) {
return this.listaProyectos.ingresarProyecto(proyecto);
}

abstract public double calcularSueldo() ;


}

package cl.ucn.ei.pa.sistemaFuncionariosProyectos.dominio;
import cl.ucn.ei.pa.sistemaFuncionariosProyectos.logica.ListaProyectos;
public class Programador extends Funcionario {
private String lenguaje;
private int horasExtra;
private int nivel;

private static int porcentajePorProyecto=20;

public Programador (String rut, String nombre, String direccion,


int sueldo, String lenguaje, int horasExtra, int nivel){
super (rut,nombre,direccion,sueldo,1);
this. lenguaje = lenguaje;
this. horasExtra = horasExtra;
this. nivel = nivel;
}
2.263
public String getLenguaje() {
return lenguaje;
}
public void setLenguaje(String lenguaje) {
this.lenguaje = lenguaje;
}
public int getHorasExtra() {
return horasExtra;
}
public void setHorasExtra(int horasExtra) {
this.horasExtra = horasExtra;
}
public int getNivel() {
return nivel;
}
public void setNivel(int nivel) {
this.nivel = nivel;
}
public double calcularSueldo(){
double suma = 0;
int monto;
double bono;
int meses;
ListaProyectos listaProyectos = this.getListaProyectos();
for (int i=0; i<listaProyectos.getCantidadProyectos();i++){
Proyecto proyecto = listaProyectos.getProyectoI(i);
monto = proyecto.getMonto();
meses = proyecto.getMeses();
bono=(monto/meses)*
(Programador.getPorcentajePorProyecto()/100);
suma = suma + bono;
}
double sueldo = this.getSueldoBase() +
5000*horasExtra+30000*nivel+suma;
return sueldo;
}
public static int getPorcentajePorProyecto() {
return porcentajePorProyecto;
}
public static void setPorcentajePorProyecto(int porcentajePorProyecto) {
Programador.porcentajePorProyecto = porcentajePorProyecto;
}
}
2.264
package cl.ucn.ei.pa.sistemaFuncionariosProyectos.dominio;
import cl.ucn.ei.pa.sistemaFuncionariosProyectos.logica.ListaProyectos;
public class Analista extends Funcionario{
private int anosExperiencia;
private static int porcentajePorProyecto=25;

public Analista (String rut, String nombre, String direccion,


int sueldo, int anosExperiencia){
super(rut,nombre,direccion,sueldo,2);
this. anosExperiencia = anosExperiencia;
}
public int getAnosExperiencia() {
return anosExperiencia;
}
public void setAnosExperiencia(int anosExperiencia) {
this.anosExperiencia = anosExperiencia;
}
public double calcularSueldo(){
double suma = 0;
int monto;
double bono;
int meses;
ListaProyectos listaProyectos = this.getListaProyectos();
for (int i=0; i<listaProyectos.getCantidadProyectos();i++){
Proyecto proyecto = listaProyectos.getProyectoI(i);
monto = proyecto.getMonto();
meses = proyecto.getMeses();
bono=(monto/meses)*
(Analista.getPorcentajePorProyecto()/100);
suma = suma + bono;
}
double sueldo = this.getSueldoBase() + 5000 * anosExperiencia
+ suma;
return sueldo;
}
public static int getPorcentajePorProyecto() {
return porcentajePorProyecto;
}
public static void setPorcentajePorProyecto(int porcentajePorProyecto){
Analista.porcentajePorProyecto = porcentajePorProyecto;
}
}
2.265
package cl.ucn.ei.pa.sistemaFuncionariosProyectos.dominio;
import cl.ucn.ei.pa.sistemaFuncionariosProyectos.logica.ListaProyectos;
public class Ingeniero extends Funcionario{
private String titulo;
private int cantidadCargas;
private static int porcentajePorProyecto=30;

public Ingeniero(String rut,String nombre, String direccion,


int sueldo, String titulo, int cantidadCargas){
super (rut,nombre,direccion,sueldo,3);
this. titulo = titulo;
this.cantidadCargas = cantidadCargas;
}

public double calcularSueldo(){


double suma = 0;
int monto;
double bono;
int meses;
ListaProyectos listaProyectos = this.getListaProyectos();
for (int i=0; i<listaProyectos.getCantidadProyectos();i++){
Proyecto proyecto = listaProyectos.getProyectoI(i);
monto = proyecto.getMonto();
meses = proyecto.getMeses();
bono=(monto/meses)*
(Ingeniero.getPorcentajePorProyecto()/100);
suma = suma + bono;
}
double sueldo = this.getSueldoBase() +
8000*this.cantidadCargas + suma;
return sueldo;
}

public String getTitulo() {


return titulo;
}
public int getCantidadCargas() {
return cantidadCargas;
}
2.266
public void setCantidadCargas(int cantidadCargas) {
this.cantidadCargas = cantidadCargas;
}
public void setTitulo(String titulo) {
this.titulo = titulo;
}
public static int getPorcentajePorProyecto() {
return porcentajePorProyecto;
}
public static void setPorcentajePorProyecto(int porcentajePorProyecto){
Ingeniero.porcentajePorProyecto = porcentajePorProyecto;
}

package cl.ucn.ei.pa.sistemaFuncionariosProyectos.dominio;

public class Proyecto {


private String codigo;
private String nombre;
private int monto;
private int meses;
private Funcionario ingeniero;
private Funcionario analista;
private Funcionario programador;

public Proyecto (String codigo,String nombre,int monto,int meses){


this.codigo = codigo;
this.nombre = nombre;
this.meses = meses;
this.monto = monto;
ingeniero =null;
analista = null;
programador = null;
}

public void setIngeniero (Funcionario ingeniero){


this.ingeniero = ingeniero;
}
public void setAnalista (Funcionario analista){
this.analista = analista;
}
2.267

public void setProgramador (Funcionario programador){


this. programador = programador;
}

public String getCodigo() {


return codigo;
}
public int getMonto() {
return monto;
}
public int getMeses() {
return meses;
}
public String getNombre() {
return nombre;
}
public Funcionario getIngeniero (){
return ingeniero;
}
public Funcionario getAnalista() {
return analista;
}
public Funcionario getProgramador() {
return programador;
}
public void setCodigo(String codigo) {
this.codigo = codigo;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public void setMonto(int monto) {
this.monto = monto;
}
public void setMeses(int meses) {
this.meses = meses;
}
}
2.268
package cl.ucn.ei.pa.sistemaFuncionariosProyectos.logica;
import cl.ucn.ei.pa.sistemaFuncionariosProyectos.dominio.Funcionario;
public class ListaFuncionarios {
private Funcionario []lf;
private int cantidadFuncionarios;
private int max;
public ListaFuncionarios(int max){
lf = new Funcionario [max];
cantidadFuncionarios = 0;
this.max = max;
}

public boolean ingresarFuncionario(Funcionario funcionario){


if (cantidadFuncionarios < max){
lf[cantidadFuncionarios]= funcionario;
cantidadFuncionarios ++;
return true;
}
else{
return false;
}
}

public int getCantidadFuncionarios(){


return cantidadFuncionarios;
}

public Funcionario getFuncionarioI(int i){


if (i >=0 && i < cantidadFuncionarios){
return lf[i];
}
else{
return null;
}
}
2.269

public Funcionario buscarFuncionario(String rut){


int i;
for(i = 0; i < cantidadFuncionarios; i++){
if (lf[i].getRut().equals(rut)){
break;
}
}
if (i == cantidadFuncionarios){
return null;
}
else{
return lf[i];
}
}
}

package cl.ucn.ei.pa.sistemaFuncionariosProyectos.logica;

import cl.ucn.ei.pa.sistemaFuncionariosProyectos.dominio.Proyecto;

public class ListaProyectos {


private Proyecto []lp;
private int cantidadProyectos;
private int max;

public ListaProyectos(int max){


lp = new Proyecto [max];
cantidadProyectos = 0;
this.max = max;
}

public boolean ingresarProyecto(Proyecto Proyecto){


if (cantidadProyectos < max){
lp[cantidadProyectos]= Proyecto;
cantidadProyectos ++;
return true;
}
else{
return false;
}
}
2.270

public int getCantidadProyectos(){


return cantidadProyectos;
}

public Proyecto getProyectoI(int i){


if (i >=0 && i < cantidadProyectos){
return lp[i];
}
else{
return null;
}
}

public Proyecto buscarProyecto(String codigo){


int i;
for(i = 0; i < cantidadProyectos; i++){
if (lp[i].getCodigo().equals(codigo)){
break;
}
}
if (i == cantidadProyectos){
return null;
}
else{
return lp[i];
}
}
}
2.271

package cl.ucn.ei.pa.sistemaFuncionariosProyectos.logica;

public interface SistemaFuncionariosProyectos {

public boolean ingresarAnalista(String rut,String nombre,


String direccion, int sueldoBase,int agnosExperiencia);

public boolean ingresarProgramador(String rut,String nombre,


String direccion, int sueldoBase, String lenguajeProgramacion,
int horasExtra, int nivelProgramador);

public boolean ingresarIngeniero(String rut, String nombre,


String direccion, int sueldoBase, String titulo,
int cantidadCargas);

public boolean ingresarProyecto(String codigo,String nombre,


int monto, int meses);

public void asociarFuncionarioProyecto (String codigoProyecto,


String rut);

public String obtenerDatosProyectos();

public String obtenerDatosFuncionarios();

public String obtenerDatosFuncionariosProyecto(String codigo);

public String obtenerDatosProyectosFuncionario(String rut);

public String obtenerDatosIngenieros();

}
2.272
package cl.ucn.ei.pa.sistemaFuncionariosProyectos.logica;

import cl.ucn.ei.pa.sistemaFuncionariosProyectos.dominio.*;

public class SistemaFuncionariosProyectosImpl implements


SistemaFuncionariosProyectos{
private ListaProyectos listaProyectos;
private ListaFuncionarios listaFuncionarios;

public SistemaFuncionariosProyectosImpl() {
this.listaProyectos = new ListaProyectos(6);
this.listaFuncionarios=new ListaFuncionarios(30);
}

public boolean ingresarAnalista(String rut,String nombre,


String direccion, int sueldoBase, int agnosExperiencia){

Funcionario elAnalista = new Analista (rut,nombre,direccion,


sueldoBase, agnosExperiencia);
boolean ingreso =
listaFuncionarios.ingresarFuncionario(elAnalista);
return ingreso;
}

public boolean ingresarProgramador(String rut, String nombre,


String direccion, int sueldoBase,
String lenguajeProgramacion, int horasExtra,
int nivelProgramador){

Funcionario elProgramador = new Programador (rut, nombre,


direccion, sueldoBase, lenguajeProgramacion,
horasExtra, nivelProgramador);
boolean ingreso =
listaFuncionarios.ingresarFuncionario(elProgramador);
return ingreso;
}
2.273

public boolean ingresarIngeniero(String rut,String nombre,


String direccion, int sueldoBase, String titulo,
int cantidadCargas){

Funcionario elIngeniero = new Ingeniero(rut,nombre,direccion,


sueldoBase, titulo, cantidadCargas);
boolean ingreso =
listaFuncionarios.ingresarFuncionario(elIngeniero);
return ingreso;
}

public boolean ingresarProyecto(String codigo,String nombre,


int monto, int meses){
Proyecto proyecto= new Proyecto(codigo, nombre,monto, meses);
boolean ingreso = listaProyectos.ingresarProyecto(proyecto);
return ingreso;
}

public void asociarFuncionarioProyecto (String codigoProyecto,


String rut){
Funcionario funcionario =
listaFuncionarios.buscarFuncionario(rut);
Proyecto proyecto =
listaProyectos.buscarProyecto(codigoProyecto);
if (funcionario != null && proyecto != null){
if (funcionario instanceof Analista){
proyecto.setAnalista(funcionario);
}
else{
if (funcionario instanceof Programador){
proyecto.setProgramador(funcionario);
}
else{
proyecto.setIngeniero(funcionario);
}
}
funcionario.agregarProyecto(proyecto);
}
else{
throw new NullPointerException("No existe proyecto y/o funcionario");
}
}
2.274

public String obtenerDatosProyectos(){


String salida = "\nDatos de todos los proyectos\n";
for(int i = 0; i<listaProyectos.getCantidadProyectos();i++){

Proyecto proyecto = listaProyectos.getProyectoI(i);


salida = salida +"codigo: "+proyecto.getCodigo()+
", nombre: "+ proyecto.getNombre()+
", meses: " + proyecto.getMeses()+
", monto mensual: " +
proyecto.getMonto()/proyecto.getMeses()+
", monto total: "+ proyecto.getMonto()+ "\n";
}
return salida;
}

public String obtenerDatosFuncionarios(){


String salida = "\nListado de funcionarios\n";
for(int i = 0;
i<listaFuncionarios.getCantidadFuncionarios();i++){

Funcionario funcionario =
listaFuncionarios.getFuncionarioI(i);

salida = salida + "rut: "+funcionario.getRut()+


", nombre: "+ funcionario.getNombre()+
", direccion: "+funcionario.getDireccion()+
", sueldo base: "+funcionario.getSueldoBase()+
", sueldo: "+funcionario.calcularSueldo()+ "\n";
}
return salida;
}
2.275

public String obtenerDatosProyectosFuncionario (String rut){


String salida = "\nProyectos del funcionario "+rut+ "\n";
Funcionario funcionario = listaFuncionarios.buscarFuncionario(rut);
if (funcionario != null){
ListaProyectos listaProyectos =
funcionario.getListaProyectos();
for(int i=0; i<listaProyectos.getCantidadProyectos();i++){
Proyecto proyecto = listaProyectos.getProyectoI(i);
salida = salida + proyecto.getNombre() + "\n";
}
return salida;
}
else {
throw new NullPointerException(
"No existe el funcionario");
}
}

public String obtenerDatosIngenieros(){


String salida = "\nDatos de los ingenieros\n";
for(int i=0; i<listaFuncionarios.getCantidadFuncionarios();i++){
Funcionario funcionario =
listaFuncionarios.getFuncionarioI(i);
if (funcionario instanceof Ingeniero){
salida = salida + "nombre "+ funcionario.getNombre();
Ingeniero ingeniero = (Ingeniero) funcionario;
salida=salida+", titulo "+ingeniero.getTitulo()+"\n";
}
}
return salida;
}
2.276

public String obtenerDatosFuncionariosProyecto(String codigo){


String salida = "\nFuncionarios del proyecto "+codigo+ "\n";
Proyecto proyecto = listaProyectos.buscarProyecto(codigo);
if (proyecto == null) {
throw new NullPointerException("No existe el proyecto");
}
else {
if (proyecto.getIngeniero()!= null) {
salida = salida + "ingeniero "+
proyecto.getIngeniero().getNombre()+ "\n";
}
if(proyecto.getAnalista()!= null) {
salida = salida + "analista "+
proyecto.getAnalista().getNombre()+ "\n";
}
if (proyecto.getProgramador()!= null) {
salida = salida + "programador "+
proyecto.getProgramador().getNombre()+ "\n";
}
}
return salida;
}

}
2.277

package cl.ucn.ei.pa.sistemaFuncionariosProyectos.logica;
import java.io.IOException;
import ucn.ArchivoEntrada;
import ucn.Registro;
import ucn.StdIn;
import ucn.StdOut;
public class App {

public static void main(String[] args) throws IOException{


SistemaFuncionariosProyectos sistema =
new SistemaFuncionariosProyectosImpl();

leerProyectos(sistema);

leerFuncionarios(sistema);

leerPersonalProyectos(sistema);

StdOut.println(sistema.obtenerDatosProyectos());

StdOut.println(sistema.obtenerDatosFuncionarios());

StdOut.print("Rut funcionario para ver sus proyectos: ");


String rut = StdIn.readString();
try{
StdOut.println(sistema.obtenerDatosProyectosFuncionario(rut));
}catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}

StdOut.print("Codigo proyecto para ver sus funcionarios: ");


String codigo = StdIn.readString();
try{
StdOut.println(sistema.obtenerDatosFuncionariosProyecto(codigo));
}catch(NullPointerException ex){
StdOut.println(ex.getMessage());
}

StdOut.println(sistema.obtenerDatosIngenieros());
}
2.278

public static void leerFuncionarios(


SistemaFuncionariosProyectos sistema) throws IOException{

ArchivoEntrada archivo =
new ArchivoEntrada("Funcionarios.txt");
boolean ingreso = true;
while(!archivo.isEndFile() && ingreso) {
Registro registro = archivo.getRegistro();
int tipo = registro.getInt();
if (tipo == 1) {//Programador
String rut = registro.getString();
String nombre = registro.getString();
String direccion = registro.getString();
int sueldoBase=registro.getInt();
String lenguaje = registro.getString();
int horasExtra=registro.getInt();
int nivel=registro.getInt();
ingreso = sistema.ingresarProgramador(rut, nombre,
direccion,sueldoBase,lenguaje,horasExtra,nivel);
if(!ingreso) {
StdOut.println("No hay espacio para mas");
}
}
else {
if(tipo == 2) {//Analista
String rut = registro.getString();
String nombre = registro.getString();
String direccion = registro.getString();
int sueldoBase=registro.getInt();
int agnosExperiencia=registro.getInt();
ingreso = sistema.ingresarAnalista(rut, nombre,
direccion,sueldoBase,agnosExperiencia);
if(!ingreso) {
StdOut.println("No hay espacio para mas ");
}
}
2.279

else {//Ingeniero
String rut = registro.getString();
String nombre = registro.getString();
String direccion = registro.getString();
int sueldoBase=registro.getInt();
String titulo = registro.getString();
int cantidadCargas=registro.getInt();
ingreso = sistema.ingresarIngeniero(rut, nombre,
direccion,sueldoBase,titulo,cantidadCargas);

if(!ingreso) {
StdOut.println("No hay espacio para mas");
}
}
}
}
archivo.close();
StdOut.println("Terminado de leer el archivo Funcionarios");
}

public static void leerProyectos(


SistemaFuncionariosProyectos sistema) throws IOException{
ArchivoEntrada archivo = new ArchivoEntrada("Proyectos.txt");
boolean ingreso = true;
while(!archivo.isEndFile() && ingreso) {
Registro registro = archivo.getRegistro();
String nombre= registro.getString();
String codigo = registro.getString();
int duracion = registro.getInt();
int costo = registro.getInt();
ingreso=sistema.ingresarProyecto(codigo,nombre,costo,duracion);
if(!ingreso) {
StdOut.println("No hay espacio para mas");
}
}
archivo.close();
StdOut.println("Terminado de leer el archivo Proyectos");
}
2.280

public static void leerPersonalProyectos(


SistemaFuncionariosProyectos sistema) throws IOException{
ArchivoEntrada archivo =
new ArchivoEntrada("FuncionariosProyectos.txt");
while(!archivo.isEndFile()) {
Registro registro = archivo.getRegistro();
String codProyecto= registro.getString();
String rut= registro.getString();
sistema.asociarFuncionarioProyecto(codProyecto, rut);
}
archivo.close();
StdOut.println("Terminado de leer FuncionariosProyectos");
}

}
2.281
Ejercicios Propuestos
A) Ejercicio: Programa para una empresa de capacitación.
“Soy el Director de una empresa de capacitación que imparte cursos en el
área de tecnología de información. Dictamos muchos cursos, cada uno de
los cuales tiene un código, un nombre y una tarifa.
Programación en UNIX y Programación SQL, son dos de nuestros cursos
más populares. Los cursos pueden durar desde un día a cuatro días. Un
instructor puede enseñar varios cursos. Pablo Rogers y María González, son
dos de nuestros principales instructores. Para cada instructor se necesita
conocer, su nombre y su número telefónico. Cada curso es impartido por un
único instructor. Primero se crea un curso, y luego se le asigna el profesor.
Los estudiantes pueden tomar varios cursos a la vez; para cada estudiante se
necesita conocer su nombre y su número telefónico. Algunos de nuestros
estudiantes y profesores en algunas ocasiones no proporcionan sus números
telefónicos.”
Para el enunciado anterior, se pide el diagrama de clases.

Las Operaciones que los objetos realizan, resultan de:


 Consultas.
 Actualizaciones.
 Procesos sobre los datos.

Se deben identificar las entidades externas que interactuan con el sistema, y


las diferentes maneras en que usan el sistema.

 Agregar, eliminar y modificar alumno.


 Agregar, eliminar y modificar curso.
 Agregar, eliminar y modificar profesor.
 Agregar, eliminar estudiante de un curso.
 Asignar, modificar un profesor a un curso.
 Encontrar todos los alumnos de un curso.
 Encontrar todos los cursos que dicta un profesor.
2.282
B) Ejercicio: Declaración del problema

El programa debe manejar información relacionada con los empleados de la


empresa, y sus datos asociados. Para cada empleado se manejan datos de:
 Rut
 Nombre
 Dirección
 Fecha de contratación
 Teléfono particular

Los empleados están asignados a un único departamento. La empresa cuenta


con varios departamentos, para los que se tienen datos de:
 Código
 Nombre
 Localización

Además, la empresa cuenta con un conjunto de vehículos, los que pueden ser
asignados a los empleados (máximo un vehículo por empleado). Para cada
vehículo se registra:
 Código
 Fecha de su última mantención
 Fecha de expiración de la revisión técnica
 Lectura del cuenta kilómetros
 Capacidad del estanque de combustible

Algunos empleados trabajan con contrato por horas. A ellos se les contrata
por una cierta cantidad de horas mensuales y se acuerda con cada uno el
precio a cancelar por hora. En el momento de pagarles se verifica la
cantidad total de horas trabajadas en el mes y si se registran horas de sobre
tiempo, se les paga 1,5 veces su precio normal por cada hora extra.

Algunos empleados trabajan con contrato a plazo indefinido, fijándoseles un


sueldo base a pagar por mes. Estos empleados tienen fijada además, una
2.283
bonificación que asciende al 25% del sueldo base y un bono de
antigüedad, que varia para cada trabajador.

Algunos empleados pertenecen a uno de los varios sindicatos que funcionan


al interior de la empresa. Cada sindicato tiene un código, un nombre, un
teléfono, una dirección y fija un monto de cuota mensual a pagar por cada
uno de sus afiliados, para ser descontada de su remuneración. Sólo los
empleados con contrato a plazo indefinido, pueden pertenecer a un sindicato.

Se necesita:

1. Ingresar datos al programa.

2. Peticiones que el sistema debe responder:

 Dado un nombre de departamento, encontrar los nombres de sus


empleados.
 Dado un nombre de empleado, encontrar el nombre de su departamento.
 Dado un nombre de empleado, encontrar (si existe), el vehículo
asignado.
 Dado un código de vehículo, encontrar el nombre del empleado que lo
usa.
 Calcular el sueldo neto mensual de un empleado horas dado.
 Calcular el sueldo neto mensual de un empleado plazo indefinido dado.
 Calcular el sueldo neto mensual de un empleado dado.
 Dado un código un código de sindicato, encontrar los nombres de sus
afiliados.
 Para cada sindicato, indicar la cantidad de sus afiliados.
 Total de empleados
 Total de empleados horas.
 Total de empleados plazo indefinido.
 Total de vehículos.
 Total de vehículos asignados a empleados horas.
2.284
 Total de vehículos asignados a empleados plazo indefinido.
 Total de vehículos asignados a los empleados hora.
 Sueldo neto mensual mayor y menor de los empleados.
 Sueldo neto mensual mayor y menor de los empleados hora.
 Sueldo neto mensual mayor y menor de los empleados plazo indefinido.
 Total cancelado en remuneraciones brutas mensuales.

También podría gustarte