Pregunta

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 estáticos abstractos.Entonces mi pregunta se centra más en la mejor solución de diseño.

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

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

Dado que mis clases AHelper, BHelper y CHelper tendrán básicamente los mismos métodos, parece tener sentido mover estos métodos a una interfaz de la que luego derivan estas clases.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 derivar todos.

Siempre podría hacer que estos métodos no sean estáticos y luego crear una instancia de los objetos primero, como

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

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

¿Fue útil?

Solución

Mirando a tu respuesta Estoy pensando en las siguientes líneas:

  • Podría simplemente tener un método estático que tome un parámetro de tipo y realice la lógica esperada según el tipo.
  • Podrías crear un método virtual en tu base abstracta, donde especificas el SQL en la clase concreta.Eso contiene todo el código común que ambos requieren (p. ej.ejecutar el comando y devolver el objeto) mientras se encapsulan los bits "especialistas" (p. ej.el SQL) en las subclases.

Prefiero la segunda opción, aunque por supuesto depende de ti.Si necesita que entre en más detalles, hágamelo saber y estaré encantado de editarlo/actualizarlo :)

Otros consejos

Si yo fuera usted, intentaría evitar la estática.En mi humilde opinión, siempre terminaba con algún tipo de problema de sincronización con la estática.Dicho esto, estás presentando un ejemplo clásico de programación genérica utilizando plantillas.Adoptaré la solución basada en plantillas de Rob Copper presentada en una de las publicaciones anteriores.

Para obtener una solución genérica a su ejemplo, 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];
}

Personalmente, quizás me preguntaría por qué cada uno de los tipos necesita tener un método estático antes de siquiera pensar más.

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

En mi experiencia con este tipo de "obstáculos", el problema no son las limitaciones del lenguaje, sino las limitaciones de mi diseño.

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

En caso afirmativo, ¿qué tal un enfoque basado en la clase de utilidad (clase con métodos estáticos públicos únicamente y sin estado)?

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

No puede sobrecargar los métodos variando solo el tipo de retorno.

Puedes usar diferentes nombres:

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

O puedes crear una clase con operadores de casting:

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 puedes llamarlo así:

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

En C# 3.0, los métodos estáticos se pueden usar en interfaces como si fueran parte de ellas mediante el uso de métodos de extensión, como 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())); 
     }
 }

¿Cómo publico comentarios sobre Stack Overflow?¿Editar mi publicación original o publicar una "respuesta"?De todos modos, pensé que podría ser útil dar un ejemplo de lo que sucede en AHelper.RetrieveByID() y BHelper.RetreiveByID().

Básicamente, ambos métodos se enfrentan a un servicio web de terceros que devuelve varios objetos genéricos (transformables) utilizando un método Query que toma una cadena pseudo-SQL como sus únicos parámetros.

Entonces, AHelper.RetrieveByID(string ID) podría verse así

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];
}

Ojalá eso ayude.Como puede ver, los dos métodos son similares, pero la consulta puede ser bastante diferente según el tipo de objeto diferente que se devuelve.

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

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

marxidad Sólo un rápido punto a tener en cuenta: Justin ya ha dicho que el SQL varía mucho dependiendo del tipo, así que he trabajado sobre la base de que podría ser algo completamente diferente dependiendo del tipo, por lo que se delega a las subclases en cuestión.Mientras que su solución combina SQL MUY firmemente al Tipo (es decir,él es el SQL).

rptonía Buen punto sobre los posibles problemas de sincronización con la estática, uno que no mencioné, así que gracias :) Además, es Rob cobre (no cobre) Por cierto;) :D ( EDITAR: Sólo pensé en mencionar eso en caso de que no fue un error tipográfico, supongo que lo será, ¡así que no hay problema!)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top