2009-06-22 11 views
12

¿Por qué existen tanto la clase abstracta como la interfaz en C# si podemos lograr la función de interfaz haciendo que todos los miembros de la clase sean abstractos?¿Por qué existen tanto la clase abstracta como la interfaz en C#?

¿Es porque:

  1. Interfaz existe para tener la herencia múltiple
  2. Se tiene sentido tener interfaz porque característica puede-DO de objeto debe ser colocado en una interfaz clase abstracta en lugar base.

Por favor, aclarar

Respuesta

26

Bueno, una clase abstracta puede especificar alguna implementación, pero por lo general no todo. (Dicho esto, es perfectamente posible proporcionar una clase abstracta sin miembros abstractos, pero muchos virtuales con implementaciones "no operativas"). Una interfaz proporciona la implementación no, simplemente un contrato.

Sin duda podría argumentar que si se permitiera la herencia múltiple de clases, las interfaces serían en gran parte inútiles.

Personalmente no me cuelgo de toda la distinción "is-a" versus "can-do" para la herencia. Nunca me da una intuición tan buena sobre qué hacer como simplemente jugar con diferentes ideas y ver cuáles se sienten más flexibles. (Por otra parte, soy un tipo "favor de composición sobre herencia" ...)

EDITAR: Al igual que la forma más conveniente de refutar el tercer punto de lbushkin en su comentario ... puede anular un método abstracto con un uno no virtual (en términos de no ser capaz de anular aún más) sellándolo:

public abstract class AbstractBase 
{ 
    public abstract void Foo(); 
} 

public class Derived : AbstractBase 
{ 
    public sealed override void Foo() {} 
} 

clases derivadas de Derived no pueden anular Foo más.

No estoy de ninguna manera sugiere quiero herencia múltiple de aplicación - pero si lo tenerlo (junto con su complejidad) a continuación, una clase abstracta que acaba contenían métodos abstractos lograría casi todo que una interfaz hace (Está el tema de la implementación explícita de la interfaz, pero eso es todo lo que puedo pensar por el momento).

+1

"favor composición sobre herencia". Bueno, hay escenarios en los que lo opuesto es más deseable, como cualquier tipo de biblioteca GUI, donde la herencia es una bendición. En mi humilde opinión, un diseño bien pensado basado en la herencia (correcta) es más útil que un diseño basado en la composición si hay suficientes jerarquías. Pero ... la herencia es más difícil que la composición en cualquier caso (¿es eso un defecto de OOP, como lo usamos hoy?) –

+2

"si se permitiera la herencia múltiple de clases, las interfaces serían en gran parte inútiles". Estoy en desacuerdo con esa afirmación. En primer lugar, las interfaces proporcionan un nivel de desacoplamiento que incluso las clases base puramente abstractas llenas de métodos virtuales no operativos no pueden proporcionar. Ayudan a separar las obligaciones contractuales de un tipo de las inevitables preocupaciones centradas en la implementación. En segundo lugar, dado que las interfaces no tienen miembros de datos, evitan el problema de la herencia de datos en forma de diamante. En tercer lugar, C# permite que los métodos que implementan una interfaz sean no virtuales (lo que puede ser útil) - las clases abstractas no. – LBushkin

+0

Lo siento Jon tiene que estar en desacuerdo con usted sobre la herencia múltiple. Como alguien que ha pasado gran parte de su vida en C++, créeme, es horrible. La mayoría de los desarrolladores en C++ ahora usan herencias múltiples de la misma manera que C#/java, es decir, una clase base principal más todo lo demás como 'mix-ins' – zebrabox

7

Ambos existen porque ambos son cosas muy diferentes. Las clases abstractas permiten la implementación y las interfaces no. Una interfaz es muy útil ya que me permite decir algo sobre el tipo que estoy construyendo (es serializable, comestible, etc.) pero no me permite definir ninguna implementación para los miembros que defino.

Una clase abstracta es más poderosa que una interfaz en el sentido de que me permite crear una interfaz de herencia a través de miembros abstractos y virtuales, pero también proporciona algún tipo de implementación predeterminada o base si así lo deseo. Sin embargo, como sabe Spiderman, con ese gran poder viene una gran responsabilidad ya que una clase abstracta es más arquitectónicamente frágil.

Nota al margen:Algo interesante a destacar es que Vance Morrrison (del equipo de CLR) ha especulado acerca de la adición implementaciones del método por defecto para las interfaces en una futura versión del CLR. Esto borrará en gran medida la distinción entre una interfaz y una clase abstracta. Ver this video para más detalles.

1

Has dado una buena respuesta. Creo que tu segunda respuesta es la verdadera razón. Si quisiera hacer un objeto Compareable, no debería tener que derivar de una clase base comparable. si piensas en todas las interfaces piensa en todas las permutaciones que tendrías para manejar las interfaces básicas como IComparable.

Las interfaces nos permiten definir un contrato en torno al comportamiento expuesto públicamente que proporciona un objeto. Las clases abstractas le permiten definir tanto el comportamiento como la implementación, que es algo muy diferente.

1

Existen interfaces para proporcionar una clase sin ninguna implementación en absoluto, por lo que .NET puede proporcionar soporte para una herencia múltiple segura y funcional en un entorno administrado.

0

Una interfaz define un contrato que debe cumplir una clase implementadora; es una manera de afirmar que "esto hace eso". Una clase abstracta es una implementación parcial de una clase que, por definición, está incompleta y necesita una derivación para completarse. Son cosas muy diferentes.

+0

La implementación de la clase abstracta en realidad ya puede estar completa; no es necesario que tenga ningún miembro abstracto. Rara vez es útil derivar de una clase abstracta y no anular nada, pero es perfectamente legal. –

+1

Ah, buen punto; aún así, la definición de "clase abstracta" significa que no se puede instanciar, por lo que debe haber una derivación para instalarla; Todavía considero que está "incompleto" porque no puedes usarlo solo. Aún así, su punto es muy relevante y bien tomado. –

0

abstractclass puede tener una implementación mientras que interface solo le permite crear un contrato que los implementadores deben seguir. Con las clases abstractas puede proporcionar un comportamiento común a sus sub clases que no puede con las interfaces.

0

Sirven dos propósitos muy diferentes.

Las clases abstractas proporcionan una forma de heredar un objeto de un contrato definido, así como permitir que se especifique el comportamiento en la clase base. Esto, desde un punto de vista teórico, proporciona una relación IS-A, en la que la clase concreta IS-A tipo específico de la clase base.

Las interfaces permiten a las clases definir un (o más de un) contrato que cumplirán. Permiten un ACTS-AS o "se puede utilizar como un" tipo de relación, a diferencia de la herencia directa. Esta es la razón por la cual, típicamente, las interfaces usarán un adjetivo como su nombre (IDisposable) en lugar de un sustantivo.

14

No es una pregunta trivial, es una muy buena pregunta y siempre pregunto a los candidatos que entrevisté.
En pocas palabras: una clase base abstracta define una jerarquía de tipos, mientras que una interfaz define un contrato.

Se puede ver que es un vs implementa un.
es decir Account podría ser una cuenta de base abstracta, ya que podría tener un CheckingAccount, un SavingsAccount, etc., todos los cuales se derivan de la clase base abstracta Account. Las clases base abstractas también pueden contener métodos, propiedades y campos no abstractos como cualquier clase normal.Sin embargo, las interfaces solo contienen métodos abstractos y propiedades que se deben implementar .

C# le derivamos de una única clase base - herencia única como java. Sin embargo, puede implementar tantas interfaces como desee, esto se debe a que una interfaz es solo un contrato que su clase se compromete a implementar.

Así que si tuviera una clase SourceFile entonces mi clase podría optar por aplicar ISourceControl que dice 'yo fielmente prometo poner en práctica los métodos y propiedades que ISourceControl requiere'

Ésta es un área grande y probablemente digno de mejor publicación que la que he dado sin embargo, tengo poco tiempo, ¡pero espero que ayude!

0

Una interfaz se utiliza para lo que una clase puede hacer, pero también se usa para ocultar algunas cosas que una clase puede hacer.

Por ejemplo, la interfaz IEnumerable<T> describe que una clase puede iterar a través de sus miembros, pero también limita el acceso a esta capacidad única. Un List<T> también puede acceder a los elementos por índice, pero cuando accede a él a través de la interfaz IEnumerable<T>, solo conoce su capacidad de iterar los miembros.

Si un método acepta la interfaz IEnumerable<T> como parámetro, eso significa que solo está interesado en la capacidad de iterar a través de los miembros. Puede utilizar varias clases diferentes con esta capacidad (como List<T> o una matriz T[]) sin la necesidad de un método para cada clase.

No solo un método acepta varias clases diferentes que implementan una interfaz, puede crear nuevas clases que implementen la interfaz y el método las aceptará felizmente.

2

Una razón importante para que existan ambos mecanismos es que C# .NET solo permite la herencia simple, no la herencia múltiple como C++. La herencia de clase le permite heredar la implementación desde un solo lugar; todo lo demás se debe lograr implementando interfaces.

Por ejemplo, supongamos que creo una clase, como la subclase Car y I en tres subclases, RearWheelDrive, FrontWheelDrive y AllWheelDrive. Ahora decido que tengo que cortar mis clases a lo largo de un "eje" diferente, como aquellos con botones de encendido y los que no. Quiero que todos los autos de botón arranque tengan un método "PushStartButton()" y los que no sean de botón tengan un método "TurnKey()" y quiera tratar los objetos de Auto (con respecto a iniciarlos) independientemente de la subclase son. Puedo definir las interfaces que pueden implementar mis clases, como IPushButtonStart e IKeyedIgnition, por lo que tengo una forma común de tratar con mis objetos que difieren de una manera que es independiente de la única clase base de la que deriva cada uno.

+0

Muy buena analogía. +1 –

0

considerar tener una fruta clase que se deriva de dos niños (de Apple & plátano) como se muestra a continuación:

class Fruit 
{ 
    public virtual string GetColor() 
    { 
     return string.Empty; 
    } 
} 

class Apple : Fruit 
{ 
    public override string GetColor() 
    { 
     return "Red"; 
    } 
} 

class Banana : Fruit 
{ 
    public override string GetColor() 
    { 
     return "Yellow"; 
    } 
} 

Tenemos una interfaz existente ICloneable en C#.Esta interfaz tiene un único método que se muestra a continuación, una clase que implementa esta interfaz garantiza que se puede clonar:

public interface ICloneable 
{ 
    object Clone(); 
} 

Ahora si quiero hacer mi de Apple clase (no plátano clase) clonable, puedo aplicar Simpley ICloneable así:

class Apple : Fruit , ICloneable 
{ 
    public object Clone() 
    { 
     // add your code here 
    } 

    public override string GetColor() 
    { 
     return "Red"; 
    } 
} 

Ahora teniendo en cuenta su argumento de la clase abstracta pura, si C# tenían una clase abstracta pura decir clonable en lugar de la interfaz IClonable así:

abstract class Clonable 
{ 
    public abstract object Clone(); 
} 

Podría ahora hacer su de Apple clase clonable heredando el resumen clonable en lugar de IClonable? como este:

// Error: Class 'Apple' cannot have multiple base classes: 'Fruit' & 'Clonable' 
class Apple : Fruit, Clonable 
{ 
    public object Clone() 
    { 
     // add your code here 
    } 

    public override string GetColor() 
    { 
     return "Red"; 
    } 
} 

No, no se puede, porque una clase no puede derivar de múltiples clases.

Cuestiones relacionadas