2010-05-20 17 views

Respuesta

7
public abstract class Request 
{ 
    // each request has its own approval algorithm. Each has to implement this method 
    public abstract void Approve(); 

    // refuse algorithm is common for all requests 
    public void Refuse() { } 

    // static helper 
    public static void CheckDelete(string status) { }  

    // common property. Used as a comment for any operation against a request 
    public string Description { get; set; } 

    // hard-coded dictionary of css classes for server-side markup decoration 
    public static IDictionary<string, string> CssStatusDictionary 
} 

public class RequestIn : Request 
{ 
    public override void Approve() { } 
} 

public class RequestOut : Request 
{ 
    public override void Approve() { } 
} 
+0

¿Por qué lo haces como un método abstracto en lugar de como una interfaz? ¿Es solo más ligero si solo tienes un par de cosas implementando la Solicitud? –

+6

¿Cómo es este un ejemplo del mundo real? – Oded

+2

Una clase abstracta puede implementar métodos, por lo que podría tener algún comportamiento predeterminado allí al que un descendiente llamaría ... no puede hacer esto con una interfaz. –

0

lo utilizó para una versión casera de Tetris, donde cada tipo tetraminos era una clase hija de la clase tetramino.

0

Es posible utilizar un método abstracto (en lugar de una interfaz) cada vez que tenga una clase base que en realidad contiene algún código aplicación, pero no hay ninguna aplicación por defecto razonable para uno o más de sus métodos:

public class ConnectionFactoryBase { 

    // This is an actual implementation that's shared by subclasses, 
    // which is why we don't want an interface 
    public string ConnectionString { get; set; } 

    // Subclasses will provide database-specific implementations, 
    // but there's nothing the base class can provide 
    public abstract IDbConnection GetConnection() {} 

} 

public class SqlConnectionFactory { 
    public override IDbConnection GetConnection() { 
     return new SqlConnection(this.ConnectionString); 
    } 
} 
0

Por ejemplo, supongamos que tiene algunas clases que corresponden a filas en su base de datos. Es posible que desee que estas clases se consideren iguales cuando su ID sea igual, porque así es como funciona la base de datos. De modo que podría hacer el ID abstracto porque eso le permitiría escribir código que usa el ID, pero no implementarlo antes de que conozca el ID en las clases concretas. De esta forma, evitas implementar el mismo método equals en todas las clases de entidad.

public abstract class AbstractEntity<TId> 
{ 
    public abstract TId Id { get; } 

    public override void Equals(object other) 
    { 
     if (ReferenceEquals(other,null)) 
      return false; 
     if (other.GetType() != GetType()) 
      return false; 
     var otherEntity = (AbstractEntity<TId>)other; 
     return Id.Equals(otherEntity.Id); 
    } 
} 
0

No soy un tipo C#. ¿Te importa si uso Java? El principio es el mismo. Usé este concepto en un juego. Calculo el valor de armadura de diferentes monstruos de manera muy diferente. Supongo que podría hacerles un seguimiento de varias constantes, pero esto es mucho más fácil conceptualmente.

abstract class Monster { 
    int armorValue(); 
} 

public class Goblin extends Monster { 
    int armorValue() { 
     return this.level*10; 
    } 
} 

public class Golem extends Monster { 
    int armorValue() { 
     return this.level*this.level*20 + enraged ? 100 : 50; 
    } 
} 
+1

Tal como está escrito, su ejemplo proporciona una justificación para usar una interfaz, pero no justifica el uso de una clase abstracta. – Brian

+0

Supongo que podría haber puesto 20 líneas más de código para hacerlo más detallado. También veo cómo podría haber usado una interfaz como Attackable que tendría (entre otros) armorValue() como miembro. Sin embargo, todavía siento que esto ilustra bastante bien el punto: tanto Goblins como Golems tienen un valor de armadura, pero debe calcularse de manera diferente. – corsiKa

1

El uso del método abstracto es muy común cuando se utiliza el Template Method Pattern. Puede usarlo para definir el esqueleto de un algoritmo y hacer que las subclases modifiquen o refinen ciertos pasos del algoritmo, sin modificar su estructura.

Eche un vistazo a un ejemplo del "mundo real" de doFactory's Template Method Pattern page.

10
public abstract class MyBaseController { 
    public void Authenticate() { var r = GetRepository(); } 
    public abstract void GetRepository(); 
} 
public class ApplicationSpecificController { 
    public override void GetRepository() { /*get the specific repo here*/ } 
} 

Esto es sólo un código ficticio que representa un cierto código del mundo real que tengo (por brevedad esto es sólo código de ejemplo)

tengo 2 aplicaciones ASP MVC que hacen cosas bastante similares. La lógica de seguridad/sesión (junto con otras cosas) ocurre igual en ambos. He abstraído la funcionalidad base de ambas en una nueva biblioteca que ambas heredan. Cuando la clase base necesita elementos que solo se pueden obtener a partir de la implementación real, los implemento como métodos abstractos. Entonces, en mi ejemplo anterior, necesito extraer información del usuario de un DB para realizar la autenticación en la biblioteca base. Para obtener la base de datos correcta para la aplicación, tengo un método abstracto GetRepository que devuelve el repositorio de la aplicación. Desde aquí, la base puede llamar a algún método en el repositorio para obtener información del usuario y continuar con la validación, o lo que sea.

Cuando se necesita realizar un cambio en la autenticación, ahora solo necesito actualizar una lib en lugar de duplicar esfuerzos en ambas. En resumen, si desea implementar algunas funcionalidades, pero no todas, una clase abstracta funciona muy bien. Si no quiere implementar ninguna funcionalidad, use una interfaz.

+2

Las dos últimas oraciones son doradas. :) – GalacticCowboy

+0

Ese fue un gran ejemplo – Vamsi

1

Las clases .NET Stream son un buen ejemplo. La clase Stream incluye la funcionalidad básica que implementan todas las secuencias y, a continuación, las secuencias específicas proporcionan implementaciones específicas para la interacción real con E/S.

1

La idea básica es tener la clase abstracta para proporcionar el esqueleto y la funcionalidad básica y simplemente dejar que la implementación concreta proporcione los detalles exactos necesarios.

Supongamos que tiene una interfaz con ... +20 métodos, por ejemplo, una interfaz de lista.

List {interface } 
    + add(object: Object) 
    + add(index:Int, object: Object) 
    + contains(object: Object): Bool 
    + get(index : Int): Object 
    + size() : Int 
    .... 

Si alguien necesita proporcionar una implementación para esa lista, debe implementar los métodos +20 todo el tiempo.

Una alternativa sería tener una clase abstracta que implemente la mayoría de los métodos y simplemente dejar que el desarrollador implemente algunos de ellos.

Por ejemplo

Implementar una lista no modificable, el programador sólo necesita extender esta clase y proporcionar implementaciones para el get (int index) y size()

AbstractList: List 
    + get(index: Int) : Object { abstract } 
    + size() : Int { abstract } 
    ... rest of the methods already implemented by abstract list 

En esta situación: get y size son métodos abstractos que el desarrollador debe implementar. El resto de la funcionalidad ya puede estar implementada.

EmptyList: AbstractList 
{ 
    public overrride Object Get(int index) 
    { 
      return this; 
    } 
    public override int Size() 
    { 
      return 0; 
    } 
} 

Si bien esta aplicación puede parecer absurdo, sería útil para inicializar una variable:

List list = new EmptyList(); 

    foreach(Object o: in list) { 
    } 

para evitar punteros nulos.

0

Un ejemplo

namespace My.Web.UI 
{ 
    public abstract class CustomControl : CompositeControl 
    { 
     // ... 

     public abstract void Initialize(); 

     protected override void CreateChildControls() 
     { 
      base.CreateChildControls(); 
      // Anything custom 

      this.Initialize(); 
     } 
    } 
} 
Cuestiones relacionadas