2008-08-18 22 views
10

En primer lugar, entiendo las razones por las que una interfaz o clase abstracta (en la terminología .NET/C#) no puede tener métodos abstractos estáticos. Mi pregunta está más centrada en la mejor solución de diseño.Métodos estáticos en una interfaz/Resumen Clase

Lo que quiero es un conjunto de clases "auxiliares" que tengan sus propios métodos estáticos, de modo que si obtengo los objetos A, B y C de un proveedor externo, puedo tener clases auxiliares con métodos como

 
AHelper.RetrieveByID(string id); 
AHelper.RetrieveByName(string name); 
AHelper.DumpToDatabase(); 

desde mis clases AHelper, BHelper y CHelper serán todos tienen básicamente los mismos métodos, parece que tiene sentido para mover estos métodos a una interfaz que estas clases se derivan de. Sin embargo, querer que estos métodos sean estáticos me impide tener una interfaz genérica o una clase abstracta de la que puedan derivarse todos ellos.

que siempre podría hacer que estos métodos no estáticos y luego instanciar los objetos primero como

 
AHelper a = new AHelper(); 
a.DumpToDatabase(); 

Sin embargo, este código no parece tan intuitivo para mí. ¿Cuáles son tus sugerencias? ¿Debo abandonar el uso de una interfaz o clase de resumen por completo (la situación en la que me encuentro ahora) o puede ser refactorizada para lograr el diseño que estoy buscando?

Respuesta

3

Buscando en your response estoy pensando en las siguientes líneas:

  • Puede tener un método estático que tome un parámetro de tipo y realice la lógica esperada según el tipo.
  • Puede crear un método virtual en su base abstracta, donde especifica el SQL en la clase concreta. De modo que contiene todo el código común requerido por ambos (por ejemplo, para ejecutar el comando y devolver el objeto) mientras encapsula los bits "especializados" (por ejemplo, el SQL) en las subclases.

Prefiero la segunda opción, aunque, por supuesto, depende de usted. Si me necesita para entrar en más detalles, por favor hágamelo saber y voy a ser feliz para editar/actualizar :)

+0

EN MIEMBRO: Primera opción sería mejor ser genérico, por lo que se puede utilizar inferencia tipo que es aún mejor. –

1

En C# 3.0, los métodos estáticos pueden ser utilizados en las interfaces como si fueran una parte de ellos mediante el uso de métodos de extensión, al igual que con DumpToDatabase() a continuación:

static class HelperMethods 
{ //IHelper h = new HeleperA(); 
    //h.DumpToDatabase() 
    public static void DumpToDatabase(this IHelper helper) { /* ... */ } 

    //IHelper h = a.RetrieveByID(5) 
    public static IHelper RetrieveByID(this ObjectA a, int id) 
    { 
      return new HelperA(a.GetByID(id)); 
    } 

    //Ihelper h = b.RetrieveByID(5)  
    public static IHelper RetrieveByID(this ObjectB b, int id) 
    { 
      return new HelperB(b.GetById(id.ToString())); 
    } 
} 
2

yo personalmente quizá preguntarse por qué cada uno de los tipos necesitan tener un método estático antes incluso de pensar más.

¿Por qué no crear una clase utlity con los métodos estáticos que necesitan compartir? (Por ejemplo ClassHelper.RetrieveByID(string id) o ClassHelper<ClassA>.RetrieveByID(string id)

En mi experiencia con este tipo de "barricadas" El problema no es las limitaciones de la lengua, pero las limitaciones de mi diseño ..

2

¿Cómo se relaciona Objecta y AHelper? ¿Es AHelper.RetrieveByID() la misma lógica que BHelper.RetrieveByID()

en caso afirmativo, ¿qué tal un enfoque de clase utilidad basada (clase con sólo métodos estáticos públicos y ningún estado)

static [return type] Helper.RetrieveByID(ObjectX x) 
0

¿Cómo puedo publicar comentarios sobre el desbordamiento de la pila? ¿Editar mi publicación original o publicar una "respuesta"? De todos modos, pensé que podría ayudar a dar un ejemplo de lo que está pasando en AHelper.RetrieveByID() y BHelper.RetreiveByID()

Básicamente, ambos de estos métodos van en contra de una tercera parte servicio web que devuelve varios un objeto genérico (colable) utilizando un método Query que toma una cadena pseudo-SQL como sus únicos parámetros.

Así, AHelper.RetrieveByID (ID de cadena) podría ser como

 
public static AObject RetrieveByID(string ID) 
{ 
    QueryResult qr = webservice.query("SELECT Id,Name FROM AObject WHERE Id = '" + ID + "'"); 

    return (AObject)qr.records[0]; 
} 

public static BObject RetrieveByID(string ID) 
{ 
    QueryResult qr = webservice.query("SELECT Id,Name,Company FROM BObject WHERE Id = '" + ID + "'"); 

    return (BObject)qr.records[0]; 
} 

Esperemos que ayuda. Como puede ver, los dos métodos son similares, pero la consulta puede ser bastante diferente en función del tipo de objeto que se devuelve.

Ah, y Rob, estoy completamente de acuerdo, esto es más que probable una limitación de mi diseño y no del idioma.:)

0

¿Está buscando comportamiento polimórfico? Entonces querrás la interfaz y el constructor normal. ¿Qué no es intuitivo acerca de llamar a un constructor? Si no necesita polimorfismo (parece que no lo usa ahora), puede seguir con sus métodos estáticos. Si se trata de envoltorios alrededor de un componente de proveedor, entonces tal vez podría intentar usar un método de fábrica para crearlos como VendorBuilder.GetVendorThing ("A") que podría devolver un objeto de tipo IVendorWrapper.

2

No puede sobrecargar los métodos variando solo el tipo de devolución.

Se pueden utilizar diferentes nombres:

static AObject GetAObject(string id); 
static BObject GetBObject(string id); 

O puede crear una clase con los operadores de fundición:

class AOrBObject 
{ 
    string id; 
    AOrBObject(string id) {this.id = id;} 

    static public AOrBObject RetrieveByID(string id) 
    { 
     return new AOrBObject(id); 
    } 

    public static AObject explicit operator(AOrBObject ab) 
    { 
     return AObjectQuery(ab.id); 
    } 

    public static BObject explicit operator(AOrBObject ab) 
    { 
     return BObjectQuery(ab.id); 
    } 
} 

Entonces se le puede llamar así:

var a = (AObject) AOrBObject.RetrieveByID(5); 
var b = (BObject) AOrBObject.RetrieveByID(5); 
3

Para una solución genérica a su ejemplo, se puede hacer esto:

public static T RetrieveByID<T>(string ID) 
{ 
    var fieldNames = getFieldNamesBasedOnType(typeof(T)); 
    QueryResult qr = webservice.query("SELECT "+fieldNames + " FROM " 
            + tyepof(T).Name 
            +" WHERE Id = '" + ID + "'"); 
    return (T) qr.records[0]; 
} 
+0

+1.Lo hago en varias librerías de consulta, especialmente las que fluyen hacia los servicios web. – jro

5

si Yo era tu, trataría de evitar cualquier estática. En mi humilde opinión, siempre terminé con algún tipo de problemas de sincronización en el camino con la estática. Dicho esto, estás presentando un ejemplo clásico de programación genérica usando plantillas. Adoptaré la solución basada en plantillas de Rob Copper presentada en una de las publicaciones anteriores.

0

marxidad Sólo un punto rápido a tener en cuenta, Justin ya ha dicho que el SQL varía mucho en función del tipo, por lo que han trabajado sobre la base de que podría ser algo completamente diferente en función del tipo, por lo tanto, delegando a las subclases en cuestión. Mientras que su solución acopla el SQL MUY estrechamente con el Tipo (es decir, es el SQL).

rptony Buen punto sobre los posibles problemas de sincronización con la estática, una que no mencionó, por lo Gracias :) Además, su Rob Cooper (no cobre) Por cierto;): D (EDIT: sólo pensé mencionaría que en caso de que no era un error tipográfico, lo espero, así que no hay problema!)

Cuestiones relacionadas