Question

Tout d’abord, je comprends les raisons pour lesquelles une interface ou une classe abstraite (dans la terminologie .NET/C#) ne peut pas avoir de méthodes statiques abstraites.Ma question est alors davantage axée sur la meilleure solution de conception.

Ce que je veux, c'est un ensemble de classes « d'assistance » qui ont toutes leurs propres méthodes statiques, de sorte que si j'obtiens les objets A, B et C d'un fournisseur tiers, je peux avoir des classes d'assistance avec des méthodes telles que

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

Étant donné que mes classes AHelper, BHelper et CHelper auront toutes fondamentalement les mêmes méthodes, il semble logique de déplacer ces méthodes vers une interface dont ces classes dérivent ensuite.Cependant, vouloir que ces méthodes soient statiques m'empêche d'avoir une interface générique ou une classe abstraite dont elles pourraient toutes dériver.

Je pourrais toujours rendre ces méthodes non statiques, puis instancier d'abord les objets tels que

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

Cependant, ce code ne me semble pas aussi intuitif.Quelles sont vos suggestions ?Dois-je abandonner complètement l'utilisation d'une interface ou d'une classe abstraite (la situation dans laquelle je me trouve actuellement) ou cela peut-il éventuellement être refactorisé pour réaliser la conception que je recherche ?

Était-ce utile?

La solution

Regarder votre réponse Je pense dans le sens suivant :

  • Vous pourriez simplement avoir une méthode statique qui prend un paramètre de type et exécute la logique attendue en fonction du type.
  • Vous pouvez créer une méthode virtuelle dans votre base abstraite, où vous spécifiez le SQL dans la classe concrète.Cela contient donc tout le code commun requis par les deux (par ex.exécutant la commande et renvoyant l'objet) tout en encapsulant les bits "spécialisés" (par ex.le SQL) dans les sous-classes.

Je préfère la deuxième option, même si cela dépend bien sûr de vous.Si vous avez besoin que j'entre plus en détail, faites-le-moi savoir et je me ferai un plaisir de modifier/mettre à jour :)

Autres conseils

Si j'étais vous, j'essaierais d'éviter toute statique.À mon humble avis, je me suis toujours retrouvé avec une sorte de problèmes de synchronisation avec la statique.Cela étant dit, vous présentez un exemple classique de programmation générique utilisant des modèles.J'adopterai la solution basée sur un modèle de Rob Copper présentée dans l'un des articles ci-dessus.

Pour une solution générique à votre exemple, vous pouvez faire ceci :

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

Personnellement, je me demanderais peut-être pourquoi chacun des types doit avoir une méthode statique avant même de réfléchir davantage.

Pourquoi ne pas créer une classe utilitaire avec les méthodes statiques qu'ils doivent partager ?(par exemple. ClassHelper.RetrieveByID(string id) ou ClassHelper<ClassA>.RetrieveByID(string id)

D'après mon expérience avec ce genre de « obstacles », le problème ne vient pas des limitations du langage, mais des limites de ma conception.

Quel est le lien entre ObjectA et AHelper ?Est AHelper.RetrieveByID() la même logique que BHelper.RetrieveByID()

Si oui, que diriez-vous d'une approche basée sur une classe utilitaire (classe avec des méthodes statiques publiques uniquement et sans état)

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

Vous ne pouvez pas surcharger les méthodes en faisant varier uniquement le type de retour.

Vous pouvez utiliser différents noms :

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

Ou vous pouvez créer une classe avec des opérateurs 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);
    } 
}

Ensuite, vous pouvez l'appeler ainsi :

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

En C# 3.0, les méthodes statiques peuvent être utilisées sur les interfaces comme si elles en faisaient partie en utilisant des méthodes d'extension, comme avec DumpToDatabase() ci-dessous :

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())); 
     }
 }

Comment publier des commentaires sur Stack Overflow ?Modifier mon message d'origine ou publier une « réponse » ?Quoi qu'il en soit, j'ai pensé qu'il pourrait être utile de donner un exemple de ce qui se passe dans AHelper.RetrieveByID() et BHelper.RetreiveByID()

Fondamentalement, ces deux méthodes se heurtent à un service Web tiers qui renvoie divers objets génériques (castables) à l'aide d'une méthode Query qui prend une chaîne pseudo-SQL comme seuls paramètres.

Ainsi, AHelper.RetrieveByID(string ID) pourrait ressembler à

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

J'espère que cela aide.Comme vous pouvez le constater, les deux méthodes sont similaires, mais la requête peut être assez différente en fonction du type d'objet renvoyé.

Oh, et Rob, je suis entièrement d'accord - c'est plus que probablement une limitation de ma conception et non du langage.:)

Recherchez-vous un comportement polymorphe ?Ensuite, vous aurez besoin de l'interface et du constructeur normal.Qu’est-ce qui n’est pas intuitif dans l’appel d’un constructeur ?Si vous n'avez pas besoin de polymorphisme (on dirait que vous ne l'utilisez pas maintenant), vous pouvez vous en tenir à vos méthodes statiques.Si ce sont tous des wrappers autour d'un composant fournisseur, vous pourriez peut-être essayer d'utiliser une méthode d'usine pour les créer comme VendorBuilder.GetVendorThing("A") qui pourrait renvoyer un objet de type IVendorWrapper.

marxité Juste un petit point à noter, Justin a déjà dit que le SQL varie beaucoup en fonction du type, j'ai donc travaillé sur la base que cela pourrait être quelque chose complètement différent en fonction du type, le déléguant ainsi aux sous-classes en question.Alors que votre solution couple le SQL TRÈS étroitement au type (c'est-à-direil est le SQL).

réptonie Bon point sur les éventuels problèmes de synchronisation avec les statiques, que je n'ai pas mentionné, alors merci :) Aussi, c'est Rob Tonnelier (pas de cuivre) BTW ;) :D ( MODIFIER: Je pensais juste que je le mentionnerais au cas où n'était pas une faute de frappe, j'imagine que c'est le cas, donc pas de problème !)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top