子类需要将Interface属性实现为static

时间:2010-08-18 16:51:11

标签: c#

我的意图是我们将来围绕第三方编写的任何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 = "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
        }
    }
}

这是我的问题。会话是当前用户线程的单例。要访问单例,我知道我们创建的所有API都需要实现的方法GetCurrentSession()(它们将如何根据API实现完全不同)我需要将属性作为静态属性来获取单身人士。

但你不能。因为您不能在接口中拥有静态成员。所以...是的,我可以取出接口模式要求,但我真的不想。

仅供参考,这不是上面的功能代码,我正在对所有这些进行初步编码,并尝试将其设计得最好。

更新

关于工厂的话题,让我退后一步,为你提供更多关于我在这里做的事情。我需要根据我正在编码的API包装器获取正确的自定义APIService对象(我为每个API包装器创建一个服务类),所以我创建了一个GetService工厂(或者至少尝试过...做了很多工厂)如下。在其中你可以看到所有方法都是静态的,属性等。

以下用法示例为:

FacebookService service = PhotoServiceFactory.CurrentPhotoUploadServiceFactory;

思考?我只是想为Session做同样的事情,但我觉得我想实际公开我从工厂回来的特定服务实例中的相关会话。例如,我可以做这样的事情:

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 个答案:

答案 0 :(得分:2)

为什么要将属性设置为静态以获取单例?实例成员可以毫无问题地获得静态成员 - 这是另一回事,这很棘手。

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

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

如果其他代码需要静态获取会话,则可以使用另一个静态成员来执行此操作。

不可否认,实例成员的设计气味只是引用静态变量(FacebookSession的任何实例有效地具有相同的会话,如果你在相同的线程)但它应该工作。

答案 1 :(得分: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
    }
}

答案 2 :(得分:1)

您可以将界面转换为类,使其成为抽象,并使所有这些方法也抽象化。然后,您可以在该抽象基类中放置您想要的任何静态字段。

答案 3 :(得分:1)

如果方法是静态的,那么就没有办法强迫孩子实现它。如果您考虑通常如何使用接口,则更有意义。典型的用例类似于:

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

答案 4 :(得分:0)

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