oop - interfaces - ejercicios clases abstractas
Clases abstractas vs. interfaces vs. mixins (7)
Clase abstracta
Una clase abstracta es una clase que no está diseñada para ser instanciada. Las clases abstractas no pueden tener implementación, alguna implementación o toda implementación. Las clases abstractas están diseñadas para permitir que sus subclases compartan una implementación común (predeterminada). Un ejemplo (pseudocódigo) de una clase abstracta sería algo como esto
abstract class Shape {
def abstract area(); // abstract (unimplemented method)
def outline_width() = { return 1; } // default implementation
}
Una subclase puede parecerse
class Rectangle extends Shape {
int height = width = 5;
def override area() = { return height * width; } // implements abstract method
// no need to override outline_width(), but may do so if needed
}
Posible uso
def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}
Si una subclase no anula los métodos no implementados, también es una clase abstracta.
Interfaz
En términos generales de informática, una interfaz es las partes de un programa expuestas a un cliente. Las clases públicas y los miembros son ejemplos de interfaces.
Java y C # tienen una palabra clave de interface
especial. Estas son más o menos una clase abstracta sin implementación. (Hay trucos sobre las constantes, las clases anidadas, la implementación explícita y los modificadores de acceso en los que no voy a entrar). Aunque la parte sobre "no implementación" ya no cabe en Java, agregaron métodos predeterminados. La palabra clave de interface
se puede ver como una reificación del concepto de interfaz.
Volviendo al ejemplo de Shape
interface Shape {
def area(); // implicitly abstract so no need for abstract keyword
def outline_width(); // cannot implement any methods
}
class Rectangle implements Shape {
int height = width = 5;
def override area() = { return height * width; }
def override outline_width() = { return 1; } // every method in interface must be implemented
}
def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}
Java y C # no permiten la herencia múltiple de clases con implementación, pero sí permiten la implementación de múltiples interfaces. Java y C # usan interfaces como una solución al problema mortal del diamante de la muerte que se encuentra en los lenguajes que permiten herencia múltiple (que en realidad no es tan letal si se maneja adecuadamente).
Mixin
Un mixin (a veces llamado rasgo) permite la herencia múltiple de clases abstractas. Los mixins no tienen la asociación aterradora que tiene la herencia múltiple (debido a la locura de C ++), por lo que las personas se sienten más cómodas usándolas. Tienen el mismo problema exacto de Diamante mortal de la muerte, pero los idiomas que los respaldan tienen formas más elegantes de mitigarlo que C ++, por lo que se perciben como mejores.
Mixins son aclamados como interfaces con la reutilización del comportamiento , las interfaces más flexibles y las interfaces más potentes . Observará que todos estos tienen el término interface
en ellos, en referencia a la palabra clave Java y C #. Mixins no son interfaces. Ellos son herencia múltiple. Con un nombre más bonito.
Esto no quiere decir que los mixins son malos. La herencia múltiple no está mal. La forma en que C ++ resuelve la herencia múltiple es lo que todos se preocupan.
En el viejo y cansado ejemplo de Shape
mixin Shape {
def abstract area();
def outline_width() = { return 1; }
}
class Rectangle with Shape {
int height = width = 5;
def override area() = { return height * width; }
}
def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}
Notará que no hay diferencia entre este y el ejemplo de la clase abstracta.
Un dato extra es que C # ha sido compatible con mixins desde la versión 3.0. Puede hacerlo con métodos de extensión en las interfaces. Aquí está el ejemplo de Shape con el estilo real (!) C # mixin style
interface Shape
{
int Area();
}
static class ShapeExtensions
{
public static int OutlineWidth(this Shape s)
{
return 1;
}
}
class Rectangle : Shape
{
int height = 5;
int width = 5;
public int Area()
{
return height * width;
}
}
class Program
{
static void Main()
{
Shape[] shapes = new Shape[]{ new Rectangle(), new Oval() };
foreach (var s in shapes)
{
Console.Write("area: " + s.Area() + ", outline width: " + s.OutlineWidth());
}
}
}
¿Podría alguien explicarme las diferencias entre clases abstractas , interfaces y mixins ? He usado cada uno antes en mi código, pero no sé las diferencias técnicas.
Básicamente, una clase abstracta es una interfaz con alguna implementación concreta. Una interfaz es solo un contrato que no tiene detalles de implementación.
Utilizaría y abstraería la clase si desea crear una funcionalidad común entre todos los objetos que implementan la clase abstracta. Manteniendo el principio DRY (No repetir) de OOP.
Dado que muchos de los chicos han explicado sobre las definiciones y el uso, me gustaría resaltar solo los puntos importantes
Interfaz:
- Para definir un contrato (preferiblemente sin estado - quiero decir sin variables)
- Para vincular clases no relacionadas con capacidades "
has a
". - Para declarar variables constantes públicas (estado inmutable)
Clase abstracta:
Compartir código entre varias clases estrechamente relacionadas. Establece
is a
relación "is a
".Compartir estado común entre clases relacionadas (el estado puede modificarse en clases concretas)
Estoy cerrando la diferencia con un pequeño ejemplo.
Animal
puede ser una clase abstracta. Cat
and Dog
, que extiende esta clase abstracta establece is a
relación " is a
".
El gato is a
animal
El perro is a
animal
Dog can
implementar la interfaz de Bark
. Entonces Dog has a
capacidad de ladrar.
Cat can
implementar la interfaz Hunt
. Entonces, Cat has a
capacidad de cazar.
El hombre , que not Animal
es not Animal
, puede implementar la interfaz de Hunt
. Entonces el hombre has a
capacidad de cazar.
El hombre y el animal (gato / perro) no están relacionados. Pero la interfaz de Hunt puede proporcionar la misma capacidad a entidades no relacionadas.
Mixin:
- Si quieres una mezcla de
abstract class
einterface
. Especialmente útil cuando se quiere forzar un nuevo contrato en muchas clases no relacionadas donde algunos de ellos tienen que redefinir el nuevo comportamiento y algunos de ellos deben apegarse a la implementación común. Agregue una implementación común en Mixin y permita que otras clases redefinan los métodos de contrato si es necesario
Si quiero declarar una clase abstracta, seguiré uno de estos dos enfoques.
Mover todos los métodos abstractos a la
interface
y mi clase abstracta implementa esa interfaz.interface IHunt{ public void doHunting(); } abstract class Animal implements IHunt{ } class Cat extends Animal{ public void doHunting(){} }
Pregunta SE relacionada:
¿Cuál es la diferencia entre una interfaz y una clase abstracta?
El significado de ''Mixin'' está excelentemente definido por Joshua Bloch en su efectivo libro de Java. Un extracto del mismo libro:
" mixin es un tipo que una clase puede implementar además de su" tipo primario "para declarar que proporciona algún comportamiento opcional. Por ejemplo, Comparable es una interfaz mixin que permite a una clase declarar que sus instancias están ordenadas con respecto a otras Objetos comparables entre sí. Dicha interfaz se denomina mixin porque permite que la funcionalidad opcional se "mezcle" con la funcionalidad principal del tipo " .
En general:
Una interfaz es un contrato que especifica operaciones, pero sin ninguna implementación. Algunos lenguajes (Java, C #) tienen soporte integrado para interfaces, y en otros ''interfaz'' describe una convención como una clase virtual pura en C ++.
Una clase abstracta es una clase que especifica al menos una operación sin implementación. Las clases abstractas también pueden proporcionar algunas partes de su implementación. Una vez más, algunos lenguajes tienen soporte incorporado para marcar clases como abstracto y está implícito en otros. Por ejemplo, en C ++ una clase que define un método virtual puro es abstracta.
Una mixin es una clase que está diseñada para facilitar la implementación de ciertas funciones en subclases, pero que no está diseñada para ser utilizada por sí misma. Por ejemplo, supongamos que tenemos una interfaz para un objeto que maneja solicitudes
interface RequestHandler {
void handleRequest(Request request);
}
Tal vez sería útil amortiguar las solicitudes acumulándolas hasta que tengamos un número predeterminado y luego limpiemos el búfer. Podemos implementar la funcionalidad de almacenamiento en búfer con un mixin sin especificar el comportamiento de descarga:
abstract class BufferedRequestHandlerMixin implements RequestHandler {
List<Request> buffer = new List<Request>();
void handleRequest(Request request) {
buffer.add(request);
if (buffer.size == BUFFER_FLUSH_SIZE) {
flushBuffer(buffer);
buffer.clear();
}
}
abstract void flushBuffer(List<Request> buffer);
}
De esta forma, es fácil para nosotros escribir un controlador de solicitudes que escribe solicitudes en el disco, llama a un servicio web, etc., sin volver a escribir la funcionalidad del búfer cada vez. Estos manejadores de solicitudes pueden simplemente extender BufferedRequestHandlerMixin
e implementar flushBuffer
.
Otro buen ejemplo de mixin es una de las muchas clases de soporte en Spring, a saber. HibernateDaoSupport .
La referencia a Java y el ejemplo dado de la clase Abstract para proporcionar mixin es engañosa. En primer lugar, Java no es compatible con "mixins" por defecto. En términos de Java, la clase abstracta y Mixins se vuelven confusas.
Un mixin es un tipo que una clase puede implementar además de su "tipo primario" para indicar que proporciona algún comportamiento opcional. Para hablar en términos de Java, un ejemplo sería su objeto de valor empresarial implementando Serializable.
Josh Bloch dice: "Las clases abstractas no se pueden usar para definir mixins, ya que una clase no puede tener más de un padre" (Recuerde que Java permite solo un candidato "extends")
Busque idiomas como Scala y Ruby para la implementación apropiada de la noción de "mixin"
Una clase abstracta es una clase en la que no se implementan todos sus miembros, se dejan para que se implementen los herederos. Obliga a sus herederos a implementar sus miembros abstractos. Las clases abstractas no se pueden instanciar y, por lo tanto, sus constructores no deberían ser públicos.]
Aquí hay un ejemplo en C #:
public abstract class Employee
{
protected Employee(){}
public abstract double CalculateSalary(WorkingInfo workingInfo);//no implementation each type of employee should define its salary calculation method.
}
public class PartTimeEmployee:Employee
{
private double _workingRate;
public Employee(double workingRate)
{
_workingRate=workingRate;
}
public override double CalculateSalary(WorkingInfo workingInfo)
{
return workingInfo.Hours*_workingRate;
}
}
Una interfaz es un contrato a ser implementado por una clase. Simplemente declara la firma de los miembros de una clase implementadora y no tiene implementación en sí misma. Usualmente usamos interfaces para implementar polimorfismo y desacoplar clases dependientes.
Aquí hay un ejemplo en C #:
public interface IShape
{
int X{get;}
int Y{get;}
void Draw();
}
public class Circle:IShape
{
public int X{get;set;}
public int Y{get;set;}
public void Draw()
{
//Draw a circle
}
}
public class Rectangle:IShape
{
public int X{get;set;}
public int Y{get;set;}
public void Draw()
{
//Draw a rectangle
}
}