Подкласс должен реализовать свойство Interface как статическое - PullRequest
3 голосов
/ 18 августа 2010

Мое намерение состоит в том, что любые проекты-обертки API, которые мы напишем в будущем вокруг сторонних или даже внутренних API, которые нуждаются в сеансе, должны будут (в соответствии с ожидаемым шаблоном команды) реализовать этот интерфейс, потому что он обеспечит общность в терминах этих API Проекты Wrapper, потому что я знаю, что любые классы сессий всегда будут содержать 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 = "http://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), мне нужно, чтобы свойство было статическим свойством, чтобы получить синглтон .

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

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

UPDATE:

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

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

FacebookService service = PhotoServiceFactory.CurrentPhotoUploadServiceFactory;

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

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
    }

Ответы [ 5 ]

2 голосов
/ 18 августа 2010

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

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
    }
}
2 голосов
/ 18 августа 2010

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

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

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

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

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

1 голос
/ 18 августа 2010

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

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

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

public class IAPISessionFactory
{
    public static IAPISession<T> GetInstance() where T : IAPISession
    {
        if(typeof(T) == typeof(ConcreteSession)
            return ConcreteSession.GetInstance();
    }
}
1 голос
/ 18 августа 2010

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

0 голосов
/ 18 августа 2010

Я не уверен на 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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...