CLASES E INTERFACES ABSTRACTAS
Una superclase define el comportamiento común de las
subclases relacionadas. Se puede usar una interfaz para definir el
comportamiento común de las clases (incluidas las clases no relacionadas).
Puede usar el método java.util.Arrays.sort para
ordenar una matriz de números o cadenas.
Clases abstractas
No se puede usar una clase abstracta para crear
objetos. Una clase abstracta puede contener métodos abstractos, que se
implementan en subclases concretas. En la jerarquía de herencia, las clases se
vuelven más específicas y concretas con cada nueva subclase. Si pasa de una subclase
a una superclase, las clases se vuelven más generales y menos específicas. El
diseño de la clase debe garantizar que una superclase contenga características
comunes de sus subclases. A veces, una superclase es tan abstracta que no se
puede usar para crear instancias específicas. Dicha clase se conoce como una
clase abstracta.
Las clases abstractas son como las clases regulares,
pero no puede crear instancias de clases abstractas utilizando el nuevo
operador. Se define un método abstracto sin implementación. Su implementación
es proporcionada por las subclases. Una clase que contiene métodos abstractos
debe definirse como abstracta. El constructor en la clase abstracta se define
como protegido, porque solo lo usan las subclases. Cuando crea una instancia de
una subclase concreta, se invoca al constructor de su superclase para inicializar
los campos de datos definidos en la superclase
Por qué métodos abstractos?
Quizás se pregunte qué ventaja se obtiene al definir
los métodos getArea () y getPerimeter () como abstractos en la clase
GeometricObject. El ejemplo en el Listado 13.4 muestra los beneficios de
definirlos en la clase GeometricObject. El programa crea dos objetos
geométricos, un círculo y un rectángulo, invoca el método equalArea para
verificar si tienen áreas iguales e invoca el método displayGeometricObject
para mostrarlos.
Puntos interesantes sobre las
clases abstractas
Vale la pena señalar los siguientes
puntos sobre las clases abstractas:
➢ Un método abstracto no
puede estar contenido en una clase no abstracta. Si una subclase de una
superclase abstracta no implementa todos los métodos abstractos, la subclase
debe definirse como abstracta. En otras palabras, en una subclase no abstracta
extendida desde una clase abstracta, todos los métodos abstractos deben implementarse.
También tenga en cuenta que los métodos abstractos no son estáticos.
➢ No se puede crear una
instancia de una clase abstracta utilizando el nuevo operador, pero aún puede
definir sus constructores, que se invocan en los constructores de sus subclases.
Por ejemplo, los constructores de GeometricObject se invocan en la clase Circle
y la clase Rectángulo.
➢ Una clase que contiene
métodos abstractos debe ser abstracta. Sin embargo, es posible definir una
clase abstracta que no contenga ningún método abstracto. En este caso, no puede
crear instancias de la clase utilizando el nuevo operador. Esta clase se usa
como una clase base para definir subclases.
➢ Una subclase puede anular
un método de su superclase para definirlo como abstracto. Esto es muy inusual,
pero es útil cuando la implementación del método en la superclase deja de ser
válida en la subclase. En este caso, la subclase debe definirse como abstracta.
➢ Una subclase puede ser
abstracta incluso si su superclase es concreta. Por ejemplo, la clase Object es
concreta, pero sus subclases, como GeometricObject, pueden ser abstractas.
➢ No puede crear una
instancia a partir de una clase abstracta utilizando el nuevo operador, pero se
puede utilizar una clase abstracta como tipo de datos. Por lo tanto, la
siguiente declaración, que crea una matriz cuyos elementos son del tipo
GeometricObject, es correcta.
GeometricObject[] objects = new
GeometricObject[10];
Interfaces
Una interfaz es una construcción de
clase que contiene solo constantes y métodos abstractos. En muchos sentidos,
una interfaz es similar a una clase abstracta, pero su intención es especificar
un comportamiento común para objetos de clases relacionadas o clases no
relacionadas. Por ejemplo, usando las interfaces apropiadas, puede especificar
que los objetos sean comparables, comestibles y / o clonables. Para distinguir
una interfaz de una clase, Java utiliza la siguiente sintaxis para definir una
interfaz:
modifier
interface InterfaceName {
/**
Constant declarations */
/**
Abstract method signatures */ }
Ejemplo de
una interfaz:
public
interface Edible {
/** Describe how to eat */
public
abstract String howToEat(); }
Una
interfaz se trata como una clase especial en Java. Cada interfaz se compila en
un archivo de bytecode separado, como una clase normal. Puede usar una interfaz
más o menos de la misma manera que usa una clase abstracta. Por ejemplo, puede
usar una interfaz como tipo de datos para una variable de referencia, como
resultado de la conversión, etc. Al igual que con una clase abstracta, no puede
crear una instancia desde una interfaz utilizando el nuevo operador. Puede usar
la interfaz comestible para especificar si un objeto es comestible. Esto se
logra dejando que la clase para el objeto implemente esta interfaz utilizando
la palabra clave implements.
La interfaz
comparable
La interfaz
comparable define el método compareTo para comparar objetos. Suponga que desea
diseñar un método genérico para encontrar el mayor de dos objetos del mismo
tipo, como dos estudiantes, dos fechas, dos círculos, dos rectángulos o dos
cuadrados. Para lograr esto, los dos objetos deben ser comparables, por lo que
el comportamiento común de los objetos debe ser comparable. Java proporciona la
interfaz comparable para este propósito. La interfaz se define de la siguiente
manera:
//
Interface for comparing objects, defined in java.lang
package
java.lang;
public
interface Comparable<E> {
public int
compareTo(E o);
}
El método
compareTo determina el orden de este objeto con el objeto especificado o y
devuelve un entero negativo, cero o un entero positivo si este objeto es menor,
igual o mayor que o. La interfaz comparable es una interfaz genérica. El tipo
genérico E se reemplaza por un tipo concreto al implementar esta interfaz.
Muchas clases en la biblioteca Java implementan Comparable para definir un
orden natural para los objetos.
La interfaz
clonable
La interfaz
clonable especifica que un objeto puede ser clonado. A menudo es deseable crear
una copia de un objeto. Para hacer esto, debe usar el método de clonación y
comprender la interfaz clonable. Una interfaz contiene constantes y métodos
abstractos, pero la interfaz clonable es un caso especial. La interfaz clonable
en el paquete java.lang se define de la siguiente manera:
package
java.lang;
public
interface Cloneable {
}
Esta
interfaz está vacía. Una interfaz con un cuerpo vacío se denomina interfaz de
marcador. Una interfaz de marcador no contiene constantes ni métodos. Se
utiliza para denotar que una clase posee ciertas propiedades deseables. Una
clase que implementa la interfaz Cloneable se marca clonable, y sus objetos se
pueden clonar utilizando el método clone () definido en la clase Object. Muchas
clases en la biblioteca de Java (por ejemplo, Fecha, Calendario y ArrayList)
implementan Cloneable.
Interfaces
vs Clases abstractas
Una clase
puede implementar múltiples interfaces, pero solo puede extender una
superclase. Una interfaz se puede usar más o menos de la misma manera que una
clase abstracta, pero definir una interfaz es diferente de definir una clase
abstracta.
Java
permite solo una única herencia para la extensión de clase, pero permite
múltiples extensiones para las interfaces. Por ejemplo:
public
class NewClass extends BaseClass
implements Interface1, ..., InterfaceN
{ ...
}
Una
interfaz puede heredar otras interfaces usando la palabra clave extend. Dicha
interfaz se llama subinterfaz. Por ejemplo, NewInterface en el siguiente código
es una subinterfaz de Interface1,. . . y InterfaceN.
public
interface NewInterface extends Interface1, ... , InterfaceN {
//
constants and abstract methods
}
Una clase
que implementa NewInterface debe implementar los métodos abstractos definidos
en NewInterface, Interface1,. . . y InterfaceN. Una interfaz puede extender
otras interfaces pero no clases. Una clase puede extender su superclase e
implementar múltiples interfaces. Todas las clases comparten una sola raíz, la
clase Object, pero no hay una sola raíz para las interfaces. Al igual que una
clase, una interfaz también define un tipo. Una variable de un tipo de interfaz
puede hacer referencia a cualquier instancia de la clase que implemente la
interfaz. Si una clase implementa una interfaz, la interfaz es como una
superclase para la clase. Puede usar una interfaz como tipo de datos y emitir
una variable de un tipo de interfaz a su subclase, y viceversa.
Pautas de
diseño de clase:
Las pautas
de diseño de clase son útiles para diseñar clases de sonido. Aprendió a diseñar
clases a partir de los dos ejemplos anteriores y de muchos otros ejemplos en
los capítulos anteriores. Esta sección resume algunas de las pautas.
Cohesión:
Una clase
debería describir una sola entidad, y todas las operaciones de la clase
deberían encajar lógicamente para apoyar un propósito coherente. Puede usar una
clase para estudiantes, por ejemplo, pero no debe combinar estudiantes y
personal en la misma clase, porque los estudiantes y el personal son entidades
diferentes. Una sola entidad con muchas responsabilidades puede dividirse en
varias clases para separar las responsabilidades. Las clases String,
StringBuilder y StringBuffer tratan todas las cadenas, por ejemplo, pero tienen
diferentes responsabilidades. La clase String trata con cadenas inmutables, la
clase StringBuilder es para crear cadenas mutables y la clase StringBuffer es
similar a StringBuilder, excepto que StringBuffer contiene métodos
sincronizados para actualizar cadenas.
Consistencia:
Siga el
estilo de programación estándar de Java y las convenciones de nombres. Elija
nombres informativos para clases, campos de datos y métodos. Un estilo popular
es colocar la declaración de datos antes del constructor y colocar los
constructores antes que los métodos. Haz que los nombres sean consistentes. No
es una buena práctica elegir nombres diferentes para operaciones similares. Por
ejemplo, el método length () devuelve el tamaño de un String, un StringBuilder
y un StringBuffer. Sería inconsistente si se usaran diferentes nombres para
este método en estas clases. En general, siempre debe proporcionar un
constructor público sin argumentos para construir una instancia predeterminada.
Si una clase no admite un constructor sin argumentos, documente el motivo. Si
no se definen explícitamente constructores, se supone un constructor público
sin argumentos con un cuerpo vacío. Si desea evitar que los usuarios creen un
objeto para una clase, puede declarar un constructor privado en la clase, como
es el caso de la clase Math.
Encapsulación:
Una clase
debe usar el modificador privado para ocultar sus datos del acceso directo de
los clientes. Esto hace que la clase sea fácil de mantener. Proporcione un
método getter solo si desea que el campo de datos sea legible, y proporcione un
método setter solo si desea que el campo de datos sea actualizable. Por
ejemplo, la clase Rational proporciona un método getter para numerador y
denominador, pero no un método setter, porque un objeto Rational es inmutable.
Claridad:
La
cohesión, la consistencia y la encapsulación son buenas pautas para lograr la
claridad del diseño. Además, una clase debe tener un contrato claro que sea
fácil de explicar y fácil de entender. Los usuarios pueden incorporar clases en
muchas combinaciones, órdenes y entornos diferentes. Por lo tanto, debe diseñar
una clase que no imponga restricciones sobre cómo o cuándo puede usarla el
usuario, diseñar las propiedades de una manera que le permita establecerlas en
cualquier orden y con cualquier combinación de valores, y diseñar métodos que
funcionen independientemente de su orden de ocurrencia.
Completo:
Las clases
están diseñadas para ser utilizadas por muchos clientes diferentes. Para ser
útil en una amplia gama de aplicaciones, una clase debe proporcionar una
variedad de formas de personalización a través de propiedades y métodos. Por
ejemplo, la clase String contiene más de 40 métodos que son útiles para una
variedad de aplicaciones.
Instancia
vs Estática:
Una
variable o método que depende de una instancia específica de la clase debe ser
una variable o método de instancia. Una variable compartida por todas las
instancias de una clase debe declararse estática. Por ejemplo, la variable
numberOfObjects en CircleWithPrivateDataFields en el Listado 9.8 es compartida
por todos los objetos de la clase CircleWithPrivateDataFields y, por lo tanto,
se declara estática. Un método que no depende de una instancia específica debe
definirse como un método estático. Por ejemplo, el método getNumberOfObjects ()
en CircleWithPrivateDataFields no está vinculado a ninguna instancia específica
y, por lo tanto, se define como un método estático. Siempre haga referencia a
variables y métodos estáticos desde un nombre de clase (en lugar de una
variable de referencia) para mejorar la legibilidad y evitar errores. No pase
un parámetro de un constructor para inicializar un campo de datos estático. Es
mejor usar un método de establecimiento para cambiar el campo de datos
estáticos.
Instancia y
estática son partes integrales de la programación orientada a objetos. Un campo
o método de datos es instancia o estático. No pase por alto por error campos o
métodos de datos estáticos. Es un error de diseño común definir un método de
instancia que debería haber sido estático
Herencia vs
Agregación:
La
diferencia entre herencia y agregación es la diferencia entre una relación is-a
y has-a. Por ejemplo, una manzana es una fruta; por lo tanto, usaría la
herencia para modelar la relación entre las clases Apple y Fruit. Una persona
tiene un nombre; por lo tanto, usaría la agregación para modelar la relación
entre las clases Persona y Nombre.
Interfaces
vs Clases abstractas:
Ambas
interfaces y clases abstractas se pueden utilizar para especificar un
comportamiento común para los objetos. ¿Cómo decides si usar una interfaz o una
clase? En general, una relación es-una fuerte que describe claramente una
relación padre-hijo debe modelarse utilizando clases. Por ejemplo, dado que una
naranja es una fruta, su relación debe modelarse utilizando la herencia de
clase. Una relación débil de es-una, también conocida como una relación de
tipo, indica que un objeto posee cierta propiedad. Una relación débil de is-a
se puede modelar usando interfaces. Por ejemplo, todas las cadenas son
comparables, por lo que la clase String implementa la interfaz Comparable. Un
círculo o un rectángulo es un objeto geométrico, por lo que Circle puede
diseñarse como una subclase de GeometricObject. Los círculos son diferentes y
comparables en función de sus radios, por lo que Circle puede implementar la
interfaz Comparable. Las interfaces son más flexibles que las clases
abstractas, porque una subclase solo puede extender una superclase pero puede
implementar cualquier cantidad de interfaces. Sin embargo, las interfaces no
pueden contener métodos concretos. Las virtudes de las interfaces y las clases
abstractas se pueden combinar creando una interfaz con una clase abstracta que
la implemente. Luego puede usar la interfaz o la clase abstracta, lo que sea
conveniente.
Bibliografia
Y. Daniel Liang. (2011). INTRODUCTION TO JAVA PROGRAMMING COMPREHENSIVE VERSION. USA: Armstrong Atlantic State University.
Comments
Post a Comment