WedX - журнал о программировании и компьютерных науках

Подкласс должен реализовать свойство интерфейса как статическое

Мое намерение состоит в том, чтобы любые проекты-оболочки API, которые мы будем писать в будущем для сторонних или даже внутренних API-интерфейсов, которым требуется сеанс, должны будут (в соответствии с ожидаемым шаблоном команды) реализовать этот интерфейс, потому что он будет обеспечивать общность с точки зрения этих проектов-оболочек API, потому что Я знаю, что любые классы сеансов всегда будут иметь в себе GetCurrentSession, RenewSession и т. д., поэтому у нас есть согласованный шаблон с точки зрения общих членов, которые должны быть реализованы для конкретных классов сеансов.

Итак, вот мой интерфейс:

/// <summary>
/// Represents an API end user based session
/// </summary>
public interface IAPISession
{
    #region Properties

    int SessionID { get; }

    /// <summary>
    /// Gets the user ID.
    /// Note: type string since userID is not always int in 3rd party APIs 
    /// </summary>
    /// <value>The user ID.</value>
    string UserID { get; }

    bool SessionHasExpired { get; }

    DateTime ExpirationDate { get; }

    void LogOut(); // expires the session & sets SessionHasExpired

    #endregion Properties

    #region Methods

    /// <summary>
    /// Renews the session by returning a brand new session 
    /// if the existing session has expired.
    /// </summary>
    /// <returns></returns>
    IAPISession RenewSession();


    /// <summary>
    /// Gets the current API session
    /// </summary>
    /// <returns></returns>
    IAPISession GetCurrentSession();

    #endregion Methods
}

Вот пример реализации:

public class FacebookSession : IAPISession
{
    private static FacebookSession _singletonInstance;

    private FacebookSession() { }

    #region Properties

    private HttpContext CurrentContext { get; set; }

    private HttpCookie CurrentSessionCookie { get; set; }

    #endregion


    #region IAPISession Members

    // Checks for a current session cookie
    public bool SessionHasExpired 
    { 
        get
        {
            return _singletonInstance == null;
        }
    }

    public IAPISession RenewSession()
    {
        throw new NotImplementedException();
    }


    /// <summary>
    /// Gets the current API session singleton instance
    /// </summary>
    /// <returns></returns>
    public static IAPISession GetCurrentSession()
    {
        if (SessionHasExpired)
        {
            return null;
        }

        // TODO: return the singleton instance here...

    }

    public void LogOut()
    {
        throw new NotImplementedException();
    }


    public int SessionID { get; private set; }

    public string UserID { get; private set; }

    public DateTime ExpirationDate { get; private set; }

    #endregion


    public void LogIn(HttpContext currentContext)
    {
        if (SessionHasExpired)
        {
            const string redirectUri = "https://localhost/Photo/FacebookOauth.aspx"; // page they will be redirected to after they auth
            string authUrl = ConfigUtil.GetAppConfigSetting("PayPalBaseUri") + "?client_id=" +
                             ConfigUtil.GetAppConfigSetting("PayPalClientID") +
                             "&redirect_uri=" + redirectUri;

            CurrentContext.Response.Redirect(authUrl); // redirect them to log in
        }
    }
}

и вот моя проблема. Сеанс — это синглтон для текущего пользовательского потока. Чтобы получить доступ к синглтону, этот метод GetCurrentSession(), который, как я знаю, нужно будет реализовать всем API, которые мы создаем (будут совершенно разными в том, КАК они будут реализованы на основе API). Мне нужно, чтобы свойство было статическим, чтобы получить синглтон.

Но ты не можешь. Потому что у вас не может быть статических членов в интерфейсе. Итак... да, я мог бы убрать требование шаблона интерфейса, но я действительно не хочу.

К вашему сведению, это не функциональный код выше, я занимаюсь своим первоначальным кодированием всего этого и пытаюсь разработать его наилучшим образом.

ОБНОВЛЕНИЕ:

Что касается темы фабрик, позвольте мне сделать шаг назад, чтобы дать вам больше информации о том, что я здесь делаю. Мне нужно было получить правильный пользовательский объект APIService (я создаю класс обслуживания для каждой оболочки API, с которой можно работать) в зависимости от того, для какой оболочки API я кодирую, поэтому я создал фабрику GetService (или, по крайней мере, попытался... сделано много заводов) как ниже. И в нем видно, что все методы статические, свойства и т.д.

Пример использования ниже:

FacebookService service = PhotoServiceFactory.CurrentPhotoUploadServiceFactory;

Мысли? Я просто пытаюсь сделать то же самое для сеанса, но чувствую, что хотел бы фактически раскрыть связанный сеанс внутри экземпляра конкретной службы, который я возвращаю с завода. Так, например, я мог бы сделать что-то вроде этого:

service.CurrentSession which would give me the current facebook singleton session.

Служба здесь относится к типу FacebookService, потому что фабрика вышла, чтобы получить ее на основе типа API, с которым я работаю (тип API — это Enum, который я создал, который имеет такие значения, как Facebook, Flickr и т. д.)

    public class PhotoServiceFactory
    {
        private static PhotoServiceFactory _singletonInstance;

        private PhotoServiceFactory(){}

        #region Properties

        public static PhotoUploadServiceFactory CurrentPhotoUploadServiceFactory
        {
            get
            {
                _singletonInstance = _singletonInstance ?? (_singletonInstance = new PhotoUploadServiceFactory());
                return _singletonInstance;
            } 
        }

        #endregion

        #region Methods

        public static IAPIService GetAPIService(APIType apiType)
        {
            IAPIService apiService = null;

            switch (apiType)
            {
                // return the right service singleton instance
                // based on the API type that we're working with
                case APIType.Facebook:
                    apiService = FacebookAPIService.CurrentFacebookAPIService;
                    break;
                case APIType.Flickr:
                    apiService = null; // service not implemented
                    break;
                case APIType.PhotoBucket:
                    apiService = null; // service not implemented
                    break;
                case APIType.Picasa:
                    apiService = null; // service not implemented
                    break;
                case APIType.Kodak:
                    apiService = null; // service not implemented
                    break;
            }

            return apiService;
        }

        #endregion
    }
c#
18.08.2010

  • Мне непонятно, как вы хотите использовать эти классы. Не могли бы вы включить пример кода, который будет вызывать эти статические методы? Возможно, в виде модульного теста? 18.08.2010
  • обязательно: elbalazo.net/post/uml3.pdf. Это не показывает, как вы могли бы вызвать GetCurrentSession, но вот как я хочу его назвать, довольно стандартно: FacebookSession.GetCurrentSession(); поэтому GetCurrentSession() является статическим и проверяет существующий экземпляр FacebookSession. Но опять же, тогда мне приходится выводить требование иметь GetCurrentSession() из контракта, если он всегда требует и требует статического доступа во всех будущих проектах (связанных или нет), которые будут реализовывать мой IAPISession, и это не делает я чувствую себя хорошо... я твердо чувствую, что этот метод должен быть там 20.08.2010

Ответы:


1

Почему вам нужно, чтобы свойство было статическим, чтобы получить синглтон? Член-экземпляр может без проблем обращаться к статическим членам — наоборот, это сложно.

// This should compile with no problems
public IAPISession GetCurrentSession()
{
    if (SessionHasExpired)
    {
        return null;
    }

    // TODO: return the singleton instance here...
}

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

По общему признанию, это немного пахнет дизайном для члена экземпляра, чтобы он ссылался только на статические переменные (любой экземпляр FacebookSession будет эффективно иметь один и тот же сеанс, если вы находитесь в том же потоке), но он должен работать .

18.08.2010
  • (это мое мышление в настоящее время, когда я работаю над этим). Чтобы вызвать GetCurrentSession, мне пришлось бы создать новый экземпляр FacebookSession, который идет вразрез с тем фактом, что это одноэлементный класс, и вы не можете создать его экземпляр, чтобы чтобы затем вызвать GetCurrentSession. Итак, скажем, где-то в коде программной части мне нужно получить/проверить текущий сеанс, потому что мне нужно использовать is. Ну, я должен подумать, что смогу просто сделать FacebookSession.GetCurrentSession(), и он либо вернет мне текущий статический сеанс, либо создаст новый и вернет его... 18.08.2010
  • @CoffeeAddict: вам следует подумать об использовании внедрения зависимостей для предоставления вашей службе своего экземпляра сеанса - пусть контейнер беспокоится о жизненном цикле, а не о реализации службы. 18.08.2010
  • спасибо Дэн, еще не добрался до IoC. Все еще пытаюсь освоиться с интерфейсами. Абстрактные классы - это кусок пирога, но включение интерфейсов, а когда и возможности не всегда ясны в начале проекта ... поэтому я сталкиваюсь с такими стенами, где мое намерение может быть в порядке, но затем сталкиваюсь с такими стенами для начинающих, как эти . 18.08.2010
  • (Правда, это немного пахнет дизайном для члена экземпляра, чтобы он ссылался только на статические переменные) Спасибо. Так что лучше не ссылаться на статические члены экземпляра? 18.08.2010
  • проверьте мою обновленную ветку выше... добавлено больше контекста того, что я пытаюсь предоставить и делать в целом за пределами сеанса. 18.08.2010
  • @CoffeeAddict: Как я уже упоминал, у вас может быть статический метод а также... метод экземпляра будет просто удовлетворять интерфейс. Конечно, просто не использовать ThreadStatic было бы другим вариантом... передать сеанс всему, что в нем нуждается. 18.08.2010
  • Но Джон, я думаю, что тогда мне придется создать экземпляр, скажем, FacebookSession, чтобы иметь возможность вызывать нестатический GetCurrentSession, и я не хочу создавать экземпляр... потому что этот класс является синглтоном, и вы создаете экземпляр внутри частного... шаблона синглтона. Если экземпляр FacebookSession уже существует, я все равно не могу его создать, чтобы вызвать GetCurrentSession, верно? Код, который должен получить этот сеанс статически, не находится внутри этого класса.. будет одним из моих классов обслуживания, возвращаемых из этой фабрики услуг. 18.08.2010
  • Я немного смущен только из-за неопытности, столь голой со мной. 18.08.2010
  • Иметь метод экземпляра было бы глупо. Мне пришлось бы создать экземпляр FacebookSession только для вызова GetCurrentSession(), чтобы получить экземпляр, плавающий в памяти самого себя! И снова, поскольку это глупо, а статический GetCurrentSession имеет смысл, это проблема, потому что теперь я не могу обеспечить соблюдение этого, будь то в контракте IAPISession! Итак, я думаю, я немного облажался, конец истории ?? Мне просто нужно понять, что нет, вы не можете включить это в контракт, даже если вы чувствуете, что статика необходима для всех наших подклассов сеанса в будущем. 20.08.2010
  • @CoffeeAddict: вам не нужно было бы создавать экземпляр FacebookSession, если бы у вас был статический метод для статического доступа и метод экземпляра для реализации интерфейса. Вы можете реализовать интерфейс явно, если хотите. Однако, если честно, я подозреваю, что лучше отказаться от вашей модели ThreadStatic. 20.08.2010
  • @John: Моя главная проблема здесь в том, что я не могу иметь статический метод в интерфейсе, и нет смысла вызывать метод экземпляра GetCurrentSession(), потому что тогда вы будете создавать объект для получения или пытаться получить экземпляр того же самого. объект, который вы только что создали. Итак, можно ли сделать вывод, что я в значительной степени облажался из-за ограничения и просто беру его и иду дальше, хотя действительно имеет смысл быть частью контракта? Каждому сеансу нужен способ добраться до него... и я хочу применить общий шаблон, которым является этот метод. 20.08.2010
  • @CoffeeAddict: Вы все еще не поняли мою мысль. Имейте статический метод в конкретном классе, когда у вас нет экземпляра. Не в интерфейсе, а в конкретном классе. Также реализуйте интерфейс с методом экземпляра, возможно, просто вызвав статический метод. Некрасиво, но требованиям соответствует. 20.08.2010
  • @John: Да, уродство - это не то, что я хотел бы сделать. Итак, мой вывод таков: то, что я пытаюсь сделать, просто невозможно... так что смиритесь с этим типом вывода, я прав? 20.08.2010
  • @CoffeeAddict: Природа [ThreadStatic] — вот откуда исходит уродство. Это принципиально несовместимо (с точки зрения элегантности) с идеей, что интерфейс обеспечивает текущую сессию. Честно говоря, странно, что сессия вообще предоставляет GetCurrentSession. 20.08.2010

  • 2

    Вы можете попробовать использовать методы расширения для интерфейсов, чтобы обеспечить общую реализацию метода интерфейса. Вы можете объявить этот метод расширения в том же пространстве имен/сборке, что и интерфейс, чтобы, когда кто-то ссылается на интерфейс, метод расширения уже был там для использования. В этой реализации вы можете использовать свой синглтон, и он будет статическим.

    public interface IAPIWrapper
    {
        string UserID { get; }
        bool SessionHasExpired { get; }
        DateTime ExpirationDate { get; }
        void LogOut(); // expires the session & sets SessionHasExpired
    
        IAPISession RenewSession();
        IAPISession GetCurrentSession();
    }
    
    public static class IAPIWrapperImpl
    {
        private static Session session = new Session(); // Instantiate singleton here
    
        // This is an extension method for the IAPISession RenewSession method
        // the this keyword before the first parameter makes this an extension method
        public static IAPISession RenewSession(this IAPIWrapper wrapper)
        {
             // implementation details
             // use session here
        }
    
        // This is an extension method for the IAPISession GetCurrentSession method
        // the this keyword before the first parameter makes this an extension method
        public static IAPISession GetCurrentSession(this IAPIWrapper wrapper)
        {
             // implementation details
             // use session here
        }
    }
    
    18.08.2010
  • Итак, в этом примере метод расширения здесь...? 18.08.2010
  • Я добавил некоторые комментарии. Просмотрите msdn.microsoft.com/en-us/library/bb383977.aspx для получения дополнительной информации о методах расширения 18.08.2010
  • спасибо, я знаю и фактически создал некоторые методы расширения в прошлом, но только не с интерфейсами. 18.08.2010
  • ах! не видел этого... понял. 18.08.2010
  • но затем, как сказал Джон, вам все равно нужно выполнить контракт интерфейса, предоставив нестатическую реализацию метода GetCurrentSession() ... так что? 18.08.2010
  • Методы расширения можно использовать как статические методы или методы экземпляра объекта, который они расширяют. Методы расширения выглядят как нестатические методы. 18.08.2010
  • Методы расширения по-прежнему не будут обеспечивать, чтобы этот метод был в контракте ... его не было бы в контракте, что было всей моей проблемой и разочарованием. Мне просто нужно принять тот факт, что я не могу поместить туда статическую информацию, но тогда как люди создают интерфейс для общих концепций сеанса, подобных этому, если это так? Я имею в виду, что вы хотели бы убедиться, что такие вещи там есть. 20.08.2010
  • Если по контракту вы имеете в виду интерфейс, то ваш интерфейс будет иметь определенный метод. Должен ли человек им пользоваться? Нет. Потребители ваших объектов не должны использовать что-либо, что вы предоставляете, если только все ваши методы не требуют, чтобы они сначала что-то сделали (получили токен сеанса, установили какое-то состояние и т. д. и т. д.). Методы расширения предназначены только для обеспечения общей реализации. для всех, кто создает объект, реализующий интерфейс. Я не уверен, что вы имеете в виду, когда говорите о контракте. 20.08.2010

  • 3

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

    18.08.2010
  • да, но я бы предпочел, чтобы это был интерфейс. Мне не нужен абстрактный класс, так как все эти члены все равно будут реализованы по-разному. 18.08.2010
  • Независимо от того, реализованы ли все члены по-разному, это совершенно не имеет отношения к использованию абстрактного класса. 18.08.2010
  • почему абстрактный класс имеет здесь какое-то значение? Вы по-прежнему не можете добавлять статические члены в абстрактный класс, и подклассы могут даже игнорировать абстрактную заглушку, если они хотят, в отличие от интерфейсов (контрактов), где вы ДОЛЖНЫ каким-то образом реализовать этот метод. 20.08.2010
  • Что вы имеете в виду, вы все еще не можете добавлять статические члены в абстрактный класс. Конечно вы можете. Но вы правы в том, что вы не можете обеспечить выполнение какого-либо контракта со статическими методами. 20.08.2010
  • Использование статических или виртуальных модификаторов в объявлении абстрактного метода является ошибкой. msdn.microsoft.com/en-us/library/ sf985hc5%28VS.71%29.aspx 20.08.2010
  • Ха-ха, очевидно, сам по себе статический метод не может быть абстрактным. Но абстрактный класс может содержать статические члены. Перечитайте то, что вы написали выше, вы все еще не можете добавлять статические члены в абстрактный класс. Это утверждение совершенно неверно. 20.08.2010

  • 4

    Если метод статичен, на самом деле нет никакого способа заставить детей реализовать его. Если вы думаете о том, как обычно используются интерфейсы, это имеет больше смысла. Типичный вариант использования выглядит примерно так:

    var myInterfaceInstance = new SomeClassThatImplementsInterface();
    myInterfaceInstance.InterfaceMethod();
    

    Мое предложение состояло бы в том, чтобы создать Factory для получения различных экземпляров Singleton IAPISession:

    public class IAPISessionFactory
    {
        public static IAPISession<T> GetInstance() where T : IAPISession
        {
            if(typeof(T) == typeof(ConcreteSession)
                return ConcreteSession.GetInstance();
        }
    }
    
    18.08.2010
  • но дело в том, что я действительно хочу, чтобы этот метод был в контракте... но поскольку этот метод обычно будет возвращать синглтон, он должен быть статическим. Я просто не хочу оставлять это вне контракта. 18.08.2010
  • (Мое предложение состояло бы в том, чтобы создать фабрику для получения различных экземпляров Singleton IAPISession.) На самом деле у меня уже есть фабрика. И я возвращаю FacebookSession с этой фабрики... Мне все еще нужно проверить, является ли он нулевым или нет (действительный сеанс или нет) 18.08.2010
  • @CoffeeAdict - это все еще ответственность конкретного объекта. Смысл бросать перед ним Фабрику состоит в том, что нам все равно, как устроен объект (и является ли он синглтоном или нет), пока он выставляется через Фабрику. Следовательно, вам не нужен GetCurrentSession в интерфейсе, потому что нам все равно, как будет создан экземпляр IAPISession, если мы получим обратно хороший экземпляр. 18.08.2010
  • проверьте мою обновленную ветку выше... добавлено больше контекста того, что я пытаюсь предоставить и делать в целом за пределами сеанса. 18.08.2010
  • @Justin - у меня нет фабрики FacebookSession, я имел в виду ServiceFactory и службу для предоставления сеанса через свойство, доступное через экземпляр службы. Но разве не полезно иметь согласованный шаблон получения сеанса из самого фактического объекта SessionObject (метод, называемый GetCurrentSession) внутри вашего класса Session по всем направлениям? С другой стороны, вы говорите, что фабрика вместо этого предоставляет ее через свой конкретный метод (фабрика теперь является абстракцией), и поскольку фабрика не является одноэлементной, вы можете получить сеанс из базового сеанса, как хотите 18.08.2010
  • @Jusin, не пытайся спорить, просто учись здесь, так что считай, что я бросаю тебе вызов, чтобы я мог понять, как сделать это лучше или чего не делать от более опытных архитекторов. 18.08.2010
  • @Justin, возвращаясь к тому факту, что я хочу, чтобы GetCurrentSession был в контракте, даже использование промежуточной фабрики по-прежнему не решает эту проблему, потому что мне нужно выполнить контракт в том смысле, что мне нужен метод экземпляра GetCurrentSession в моем объекте SessionObject 18.08.2010
  • @CoffeeAddict - Дело в том, что использование Factory скрывает необходимость в GetCurrentSession. Каждый объект может реализовать свой собственный способ получения экземпляра самого себя. Вы полагаетесь на то, что Фабрика назовет правильный номер для вас. 18.08.2010
  • хорошо, спасибо. Позвольте мне подумать, что... мой разум идет против ваших намерений, потому что я просто хочу, чтобы все сеансы обязательно имели GetCurrentSession, независимо от того, доставляет ли его фабрика или сам объект сеанса. Хорошо иметь прослойку между фабрикой, но я должен больше думать об этом с точки зрения исключения этого из контракта. Мне просто кажется правильным, что метод getCurrentsession находится в контракте для меня... когда я думаю об общем объекте сеанса и его обязанностях. 18.08.2010
  • Дело в том, что, Джастин, я хочу навязать определенный шаблон. Использование фабрики - это то, что я буду делать. Оставить реализацию до подкласса в том, как вы получаете сеанс? Да. Но не полностью. Я хочу, чтобы новые классы как минимум выставляли его через метод GetCurrentSession, и именно таким будет наш шаблон. Таким образом, реализация может быть любой, но я хочу убедиться, что мы знаем, что все наши сеансовые классы имеют этот шаблон, указанный в интерфейсе. Например, я мог бы сказать новому разработчику: «Эй, его легко использовать, потому что у нас есть метод под названием x, который дает вам это по всем направлениям». 20.08.2010

  • 5

    Я не уверен на 100%, что вы ищете, но вы можете использовать статику с интерфейсом. Вместо этого используя

    public static IAPISession GetCurrentSession()
    {
        if (SessionHasExpired)
        {
            return null;
        }
    
        // TODO: return the singleton instance here...
    
    }
    

    Чтобы соответствовать определению интерфейса, вы должны реализовать это в частном порядке и предоставить его интерфейсу.

    private static IAPISession GetTheCurrentSession()
    {
        if (SessionHasExpired)
        {
            return null;
        }
    
        // TODO: return the singleton instance here...
    
    }
    
    public IAPISession GetCurrentSession()
    {
    return GetTheCurrentSession();
    }
    
    18.08.2010
  • Это пахнет для меня - это означает, что вам нужно будет создать экземпляр класса для доступа к статическому методу. 18.08.2010
  • Да, мне не нужно создавать экземпляр для доступа к статическому методу, я согласен. Мне это не нравится. 18.08.2010
  • Чтобы получить доступ к значению через интерфейс, у вас должен быть экземпляр. Тот, кто проголосовал за меня, явно не понимает С#. 19.08.2010
  • Новые материалы

    Как создать диаграмму градиентной кисти с помощью D3.js
    Резюме: Из этого туториала Вы узнаете, как добавить градиентную кисть к диаграмме с областями в D3.js. Мы добавим градиент к значениям SVG и применим градиент в качестве заливки к диаграмме с..

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

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

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..


    Для любых предложений по сайту: [email protected]