No es un bug, es una característica no documentada

martes, 14 de abril de 2015

Programación. Desarrollo de software orientado a objetos (I)

23:40 Posted by Inazio , No comments

Una arquitectura basada en capas

Cuando desarrollamos una aplicación podemos asemejar la tarea a la construcción de un edificio.


Un proyecto de software orientado a objetos SIEMPRE debe basarse en capas.


Cada capa tiene una responsabilidad definida:
è El usuario solicita un servicio mediante la capa de presentación
è El sistema resuelve la petición en la capa de negocio
è La capa del negocio se apoya en la capa de persistencia que se encarga de guardar y recupear objetos de la base de datos.

En cada capa deben crearse las clases y objetos necesarios:
è Presentación: VentanaPrincipa, MenuEdicion, BotonAceptar, BotonImprimir… Jurame, JButton, JMenu, ActionEvent, KeyEvent…
è Negocio: Connection, ResultSet, Statement…

Pueden crearse tantas capas como sean requeridas (normalmente tres o más).

La ingeniería del software orientada a objetos

Se encarga de desarrollar productos de software de calidad en un tiempo y coste pactados de antemano.

Según el enfoque que adoptemos al modelar el problema hablamos de Ingeniería de software:
è Estructurada. El ladrillo es el concepto de función y la librería o módulo que las agrupa.
Técnicas. Diagramas de flujo de datos, entidad – relación, diagramas de Constantine, pseudocódigos…
è Orientada a objetos. El ladrillo que usamos es la clase / objeto y el paquete como elemento contenedor.
Técnicas. Diagramas de casos de uso, de clases, de secuencia, de colaboración, mapeo de objetos a bases de datos relacionales…

La mayoría de las técnicas usadas para modelar un problema con orientación a objetos suelen plasmarse en diagramas UML (Unified Modelling Language).

Los diagramas UML los podemos clasificar según el modelado que hacen del sistema:
è Modelo de requisitos. Diagramas de casos de uso
è Modelo estático. Diagrama de clases
è Modelo dinámico. Diagramas de secuencia

Durante el curso hemos creado diagramas de clases con notación UML, que representan la vista estática del sistema.

Una metodología de desarrollo concreta las fases, tareas, técnicas y productos que se deben realizar para obtener un producto de calidad.


Un paseo por la API

Fecha y hora

Las clases que necesitamos son:
è Date. Representa un instante de tiempo específico con precisión de milisegundos
è Calendar. Es una colección de propiedades y métodos que facilitan el trabajo con instantes de tiempo
è GregorianCalendar. Implementa los métodos abstractos heredados de Calendar tomando como referencia el calendario gregoriano (usado en casi todo el mundo).


Date. Actualmente deprecated
Calendar. Al ser demasiado abstracta no podemos crear un objeto de la clase Calendar, sino que tendremos que hacerlo a través de GregorianCalendar.

GregorianCalendar ahoraCal = new GregorianCalendar();

O bien

Calendar ahoraCal = new GregorianCalendar();

Propiedades públicas y estáticas de Calendar:

·         YEAR. Año
·         MONTH. Mes, entre 0 y 11
·         DAY_OF_MONTH. Día del mes
·         DAY_OF_WEEK. Día de la semana entre 1 (Sunday) y 7 (Saturday)
·         HOUR. Hora antes o después del medio día (en intervalos de doce horas).
·         HOUR_OF_DAY. La hora absoluta del día (en intervalos de 24 horas)
·         MINUTE. El minuto dentro de la hora
·         SECOND. El segundo dentro del minuto
·         Y muchos más…

Métodos útiles

+ int get(int campo)

Ejemplo

int dia, mes, anio;
GregorianCalendar ahoraCal = GregorianCalendar();
anio = ahoraCal.get(Calendar.YEAR);
mes = ahoraCal.get(Calendar.MONTH);
dia = ahoraCal.get(Calendar.DAY_OF_MONTH);
System.out.println(“Hoy es ” + dia + “/” + mes + “/” + anio);

Para establecer valores de una fecha

+ void set(int anio, int mes, int dia)
+ void set(int anio, int mes, int dia, int hora, int min, int seg);
+ void set(int campo, int nuevoValor);

Para sumar o restar tiempo a una fecha

+ void add(int campo, int cantidad);

Ejemplo

GregorianCalendar calen = -GregorianCalendar();
calen.add(Calendar.YEAR, -1);
System.out.prinln(“Año pasado = ” + calen.get(Calendar.YEAR);

Para comparar instantes temporales (igual que Date)

+ boolean before(Calendar instante);
+ boolean after(Calendar instante);
+ boolean equals(Calendar instante);

GregorianCalendar ahora = new GregorianCalendar();
System.out.pritln(“El coche ha parado el motor a las ” + ahora.get(Calendar.HOUR_OF_DAY) + “ “ + ahora.get(Calendar.MINUTE) + “:” + ahora.get(Calendar.SECOND));

Las clases envoltorio de los tipos primitivos

Los tipos primitivos (int, doublé, boolean) no son objetos, sin embargo en ciertas ocasiones nos podría interesar que lo fuesen.

En el paquete java.lang se incluye un conjunto de clases que envuelven a cada tipo primitivo, dotándolo de métodos y propiedades útiles.

Number y su descendencia

Number es una clase abstracta que define seis métodos que convierten los números de un formato a otro:

int intValue(); // Devuelve el valor envuelto convertido a int
double doubleValue(); // Devuelve el valor envuelto convertido a doublé

Tomemos integer como ejemplo de subclase de Number y veamos que nos ofrece.

Propiedades públicas y estáticas para consultar el mínimo y máximo número representable por un int.

è MAX_VALUE
è MIN_VALUE

Constructores:

integer(int valor);
integer(String cadena) throws NumberFormatException;

Métodos estáticos para la conversión de String a int

static int parseInt(String cadena) throws NumerFormatException;
static int parseInt(String cadena, int base) throws NumberFormatException;

Ejemplos

integer.parseInt(“123”); à devuelve 123
integer.parseInt(“11111111”); à Devuelve 255
integer.parseInt(“FF”,16); à Devuelve 255
integer.parseInt(“FF”,10); à NumberFormatException

Además de los métodos heredados de Nuber hay más métodos que se pueden consultar en la API.

Ahora vamos a fijarnos en la clase Caracter que envuelve a un char (carácter en Unicode).

Aquí se presenta un conjunto de métodos estáticos muy útiles

static int getNumericValue(char c);
static boolean isDigit(char c);
static boolean isletter(char c);
static boolean isLetterOrDigit(char c);
static boolean isLowerCase(char c);
static boolean isUpperCase(char c);
static char toLowerCase(char c);

Ejemplo

char c = ‘9’;
int entero;
if (caracter.isDigit(c))
   entero = carácter.getNumericValue(c);
else
   c = carácter.toUpperCase(c);

La entrada y salida en Java. Los streams

La entrada y salida de un programa se refiere a las comunicaciones que tiene dicho programa con “su entorno” (usuario, ficheros, red, pantalla, otros programas…)

Al igual que en C y C++, Java usa el concepto de stream para gestionar las comunicaciones.

Un stream representa a una corriente o flujo de datos que sale o entra en nuestro programa.

Clasificicación de los Streams

Según la dirección a la que viajan los datos:
è De entrada
è De salida

Según el tipo de dato que manejan:
è De bytes (8 bits)
è De caracteres (en Unicode: 16 bits o más).
è De líneas de caracteres
è De datos
è De objetos

Según su comportamiento
è Transportadores. Se limitan al transporte de los datos
è Transformadores. Cambian los datos y los transportan
è Retenedores. Almacenan datos y los transportan

En el paquete java.io se concentran la mayoría de las clases que representan streams en Java.

Streams de ENTRADA basados en bytes

InputStream{abstracta}
   ByteArrayInputStream // 1
   ObjectInputStream // 1
   FileInputStream // 1
   FilterInputStream // 2
     DataInoutStream // 3
     BufferedInputStream // 4

Significados:
1.      Proporciona al programa un flujo de bytes procedentes de un array, un objeto o un fichero
2.      Esta clase y su descendencia son streams transformadores
3.      Permite leer de una vez datos primitivos (int, double, boolean…), no bytes a byte
4.      Permite almacenar en un buffer los byte leídos de otro stream  de entrada de bytes

Streams de ENTRADA basados en caracteres UNICODE

Reader{abstracta}
   StringReader // 1
   BufferedReader //2
   InputStreamReader // 3
     FileReader // 4

Significados:
1.      Proporciona al programa un flujo de caracteres UNICODE procedentes de un objeto String
2.      Permite almacenar en un buffer los caracteres UNICODE leídos de otro stream de entrada de caracteres
3.      Permite transformar a caracteres UNICODE los bytes de un stream basados en bytes, teniendo en cuenta la codificación local de caracteres
4.      Permite la lectura directa de caracteres de un fichero de texto

Streams de SALIDA basasdos en bytes

OutputStream{abstracta}
   ByteArrayOutputStream
   ObjectOutputStream
   FileOutputStream
   FilterOutputStream
     DataOutputStream
     BufferedOutputStream

Streams de SALIDA de caracteres UNICODE

Writer{abstracta}
   PrintWriter
   BufferedWiter
   OutputStreamWriter
     FileWriter

Los streams se pueden concetar unos con otros, combinando sus funcionalidades.
Ejemplo:
Partimos de un flujo de bytes de entrada.
Ahora lo combinamos con otro que convierte los bytes a caracteres UNICODE.
Y por último, lo combinamos con otro que es capaz de almacenar en un buffer dichos caracteres.

Esto es precisamente lo que hay que hacer para poder leer datos que el usuario introduce por teclado.

La clase System que representa al sistema nos devuelve un stream de bytes a través de su propiedad estática in.


A continuación convertimos el stream de bytes obtenido a un stream de caracteres UNICODE mediante la clase InputStreamReader.

InputStreamReader isr = new InputStreamReader(System.in);

Con lo que obtendríamos


Por último lo combinamos con BufferedReader que es capaz de almacenar los caracteres leídos en un buffer, mejorando la eficacia en el acceso al teclado.

BufferedReader teclado = new BufferedReader(isr);


Ahora podríamos usar el stream teclado para leer caracteres UNICODE de forma eficiente.

Ejemplo:

String cadena = teclado.readLine();
// Lee hasta encontrar un INTRO
// Lee cualquier caracter del alfabeto español

Clase teclado

import java.io.*
public class Teclado{
   private InputStreamReader filtro;
   private BufferedReader teclado;

   public Teclado(){
     filtro = new InputStreamReader(System.in);
     teclado = new BufferedReader(filtro);
   }

   public String.leerString(String cadena) throws IOException{
     System.out.println(cadena); // Pedir que debe escribir el usuario
     return (teclado.readLine());
   }

   public byte leerByte() throws IOException{
     return(Byte.parseByte(teclado.readLine());
   }

   public char leerChar(){
     return ((char) teclado.read());
   }
}

Teclado teclado = new Teclado();

try{
   String cadena = teclado.leerString(“Ruta del fichero”);
   File fichero = new File(cadena);
   if (fichero.exists()){
     System.out.println(rutaCompila + fichero.getAbsolutePath() + “es fichero ” + fichero.isFile() + “es directorio” + fichero.isDirectory() + “se puede leer ” + fichero.canRead() + “se puede escribir ” +fichero.canwrite());
   }
   else
     System.out.println(“fallo en entrada / salida”);
}
catch(IOException e){
   System.out.println(“Fallo en entrada / salida”);
}

0 comentarios:

Publicar un comentario