我的意图是我们将来围绕第三方编写的任何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
}
答案 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();
}