Статические методы в интерфейсе / абстрактном классе



Во-первых, я понимаю причины, по которым интерфейс или абстрактный класс (в терминологии .NET/C#) не может иметь абстрактных статических методов. Мой вопрос тогда больше сосредоточен на лучшем дизайнерском решении.



Мне нужен набор "вспомогательных" классов, которые все имеют свои собственные статические методы, такие что если я получаю объекты A, B и C от стороннего поставщика, я могу иметь вспомогательные классы с такими методами, как




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


Поскольку мои классы AHelper, BHelper и CHelper будут в основном имея те же методы, кажется, имеет смысл переместить эти методы в интерфейс, из которого эти классы затем выводятся. Однако желание, чтобы эти методы были статическими, не позволяет мне иметь универсальный интерфейс или абстрактный класс для всех из них, производных от.



Я всегда могу сделать эти методы нестатическими, а затем сначала создать экземпляр объектов, таких как




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


Однако этот код не кажется мне таким интуитивным. Каковы ваши предложения? Должен ли я отказаться от использования интерфейс или абстрактный класс в целом (ситуация, в которой я сейчас нахожусь), или это может быть переработано для выполнения дизайна, который я ищу?
640   10  

10 ответов:

Глядя на Ваш ответ я думаю примерно так:

  • Вы можете просто иметь статический метод, который принимает параметр типа и выполняет ожидаемую логику, основанную на типе.
  • Вы можете создать виртуальный метод в абстрактной базе, где вы указываете SQL в конкретном классе. Таким образом, он содержит весь общий код, который требуется для обоих (например, выполнение команды и возврат объекта) при инкапсуляции "специальных" битов (например, SQL) в подклассах.

Я предпочитаю второй вариант, хотя он, конечно, зависит от вас. Если вам нужно, чтобы я углубился в детали, пожалуйста, дайте мне знать, и я буду рад редактировать / обновлять :)

На вашем месте я бы постарался избежать любой статики. ИМХО я всегда заканчивал с какими-то проблемами синхронизации по дороге со статикой. Тем не менее, вы представляете классический пример универсального программирования с использованием шаблонов. Я возьму на вооружение шаблонное решение Роба Коппера, представленное в одном из постов выше.

Для общего решения вашего примера вы можете сделать следующее:

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

Я лично, возможно, задался бы вопросом, почему каждый из типов должен иметь статический метод, прежде чем даже думать дальше..

Почему бы не создать класс utlity со статическими методами, которые они должны совместно использовать? (например, ClassHelper.RetrieveByID(string id) или ClassHelper<ClassA>.RetrieveByID(string id)

В моем опыте работы с такого рода" дорожными заграждениями " проблема заключается не в ограничениях языка, а в ограничениях моего дизайна..

Как связаны ObjectA и AHelper? Является ли AHelper.RetrieveByID() той же логикой, что и BHelper.RetrieveByID()

Если да, то как насчет подхода на основе служебного класса (класс только с открытыми статическими методами и без состояния)

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

Нельзя перегружать методы, изменяя только тип возвращаемого значения.

Вы можете использовать разные имена:

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

Или можно создать класс с операторами приведения:

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

Тогда вы можете назвать его так:

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

В C# 3.0 статические методы могут использоваться на интерфейсах, как если бы они были их частью, используя методы расширения, как в случае с DumpToDatabase () ниже:

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

Как разместить отзыв о переполнении стека? Отредактируйте мое оригинальное сообщение или опубликуйте "ответ"? Во всяком случае, я подумал, что это может помочь дать пример того, что происходит в Ахелпере.Ретроавтобусов() и BHelper.RetreiveByID ()

В основном, оба эти метода идут против стороннего веб-сервиса, который возвращает различные универсальные (кастабельные) объекты, используя метод запроса, который принимает в псевдо-SQL строку в качестве единственных параметров.

Итак, Ахелпер.Ретроавтобусов(идентификатор строки) может выглядеть как

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

Надеюсь, это поможет. Как вы можете видеть, эти два метода похожи, но запрос может быть довольно сильно отличаться в зависимости от возвращаемого типа объекта.

О, и Роб, я полностью согласен - это, скорее всего, ограничение моего дизайна, а не языка. :)

Вы ищете полиморфное поведение? Тогда вам понадобится интерфейс и обычный конструктор. Что неинтуитивного в вызове конструктора? Если вам не нужен полиморфизм (звучит так, как будто вы не используете его сейчас), то вы можете придерживаться своих статических методов. Если все это обертки вокруг компонента поставщика, то, возможно, вы можете попробовать использовать фабричный метод для их создания, как VendorBuilder.GetVendorThing("A"), который может возвращать объект типа IVendorWrapper.

Марксидад просто быстрый момент, чтобы отметить, Джастин уже сказал, что SQL сильно меняется в зависимости от типа, поэтому я работал на основе того, что это может быть что-то полностью другое, зависящее от типа, следовательно, делегируя его в рассматриваемые подклассы. Тогда как ваше решение связывает SQL Очень плотно к типу (т. е. этоявляется SQL).

Rptony хорошая точка зрения на возможные проблемы синхронизации со статикой, которую я не смог упомяните, так что спасибо:) Кроме того, его Rob Cooper (не медь) кстати;): D (EDIT: просто подумал, что я упомяну, что в случае, если это не было опечаткой, я ожидаю, что это так, так что нет проблем!)

Comments

    Ничего не найдено.