Pergunta

Primeiramente, entendo os motivos pelos quais uma interface ou classe abstrata (na terminologia .NET/C#) não pode ter métodos estáticos abstratos.Minha pergunta é então mais focada na melhor solução de design.

O que eu quero é um conjunto de classes "auxiliares" que tenham seus próprios métodos estáticos, de modo que, se eu obtiver os objetos A, B e C de um fornecedor terceirizado, eu possa ter classes auxiliares com métodos como

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

Como minhas classes AHelper, BHelper e CHelper terão basicamente os mesmos métodos, parece fazer sentido mover esses métodos para uma interface da qual essas classes derivam.No entanto, querer que esses métodos sejam estáticos me impede de ter uma interface genérica ou uma classe abstrata da qual todos eles possam derivar.

Eu sempre poderia tornar esses métodos não estáticos e então instanciar os objetos primeiro, como

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

No entanto, este código não me parece tão intuitivo.Quais são suas sugestões?Devo abandonar completamente o uso de uma interface ou classe abstrata (a situação em que estou agora) ou isso pode ser refatorado para realizar o design que estou procurando?

Foi útil?

Solução

Olhando para sua responsabilidade Estou pensando nas seguintes linhas:

  • Você poderia apenas ter um método estático que usa um parâmetro de tipo e executa a lógica esperada com base no tipo.
  • Você poderia criar um método virtual em sua base abstrata, onde você especifica o SQL na classe concreta.Portanto, contém todo o código comum exigido por ambos (por exemplo,executando o comando e retornando o objeto) enquanto encapsula os bits "especialistas" (por exemploo SQL) nas subclasses.

Eu prefiro a segunda opção, embora isso dependa de você.Se precisar que eu entre em mais detalhes, entre em contato e terei prazer em editar/atualizar :)

Outras dicas

Se eu fosse você, tentaria evitar qualquer estática.IMHO, sempre acabei com algum tipo de problema de sincronização com a estática.Dito isto, você está apresentando um exemplo clássico de programação genérica usando modelos.Adotarei a solução baseada em template de Rob Copper apresentada em um dos posts acima.

Para uma solução genérica para o seu exemplo, você pode fazer o seguinte:

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

Eu pessoalmente questionaria por que cada um dos tipos precisa ter um método estático antes mesmo de pensar mais.

Por que não criar uma classe utilitária com os métodos estáticos que eles precisam compartilhar?(por exemplo. ClassHelper.RetrieveByID(string id) ou ClassHelper<ClassA>.RetrieveByID(string id)

Na minha experiência com esse tipo de "obstáculos", o problema não são as limitações da linguagem, mas as limitações do meu design.

Como ObjectA e AHelper estão relacionados?É AHelper.RetrieveByID() a mesma lógica que BHelper.RetrieveByID()

Se sim, que tal uma abordagem baseada em classe Utility (classe apenas com métodos estáticos públicos e sem estado)

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

Você não pode sobrecarregar métodos variando apenas o tipo de retorno.

Você pode usar nomes diferentes:

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

Ou você pode criar uma classe com operadores de conversão:

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

Então você pode chamá-lo assim:

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

No C# 3.0, métodos estáticos podem ser usados ​​em interfaces como se fossem parte delas usando métodos de extensão, como DumpToDatabase() abaixo:

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

Como faço para postar comentários sobre o Stack Overflow?Editar minha postagem original ou postar uma "resposta"?De qualquer forma, pensei que poderia ajudar dar um exemplo do que está acontecendo em AHelper.RetrieveByID() e BHelper.RetreiveByID()

Basicamente, ambos os métodos vão contra um serviço da web de terceiros que retorna vários objetos genéricos (castable) usando um método Query que usa uma string pseudo-SQL como seus únicos parâmetros.

Então, AHelper.RetrieveByID(string ID) pode parecer

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

Espero que isso ajude.Como você pode ver, os dois métodos são semelhantes, mas a consulta pode ser um pouco diferente com base no tipo de objeto retornado.

Ah, e Rob, concordo plenamente - é mais do que provável que isso seja uma limitação do meu design e não da linguagem.:)

Você está procurando comportamento polimórfico?Então você vai querer a interface e o construtor normal.O que não é intuitivo em chamar um construtor?Se você não precisa de polimorfismo (parece que você não o usa agora), então você pode continuar com seus métodos estáticos.Se todos esses são wrappers em torno de um componente do fornecedor, talvez você possa tentar usar um método de fábrica para criá-los, como VendorBuilder.GetVendorThing("A") que pode retornar um objeto do tipo IVendorWrapper.

Marxidade Apenas um ponto rápido para observar, Justin já disse que o SQL varia muito dependendo do tipo, então trabalhei na base de que poderia ser algo completamente diferente dependendo do tipo, delegando-o assim às subclasses em questão.Considerando que sua solução une o SQL MUITO firmemente ao Tipo (ou seja,isto é o SQL).

rptony Bom ponto sobre os possíveis problemas de sincronização com estática, um que não mencionei, então obrigado :) Além disso, é Rob Tanoeiro (não cobre) Aliás;) :D ( EDITAR: Apenas pensei em mencionar isso caso não foi um erro de digitação, espero que seja, então não há problema!)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top