有条件的解决是我目前不了解的最后一件事。
可以说我们有一个接口IAuthenticate:
IAuthenticate
public interface IAuthenticate{ bool Login(string user, string pass); }
现在,我有两种身份验证。
Twitter身份验证
public class TwitterAuth : IAuthenticate { bool Login(string user, string pass) { //connect to twitter api } }
Facebook身份验证
public class FacebookAuth: IAuthenticate { bool Login(string user, string pass) { //connect to fb api } }
在unity config中注册类型:
unityContainer.RegisterType<IAuthenticate, TwitterAuth>(); unityContainer.RegisterType<IAuthenticate, FacebookAuth>();
通过DI在我们的控制器中注入对象:
private readonly IAuthenticate _authenticate; public AuthenticateController(IAuthenticate authenticate) { _authenticate = authenticate; } // login with twitter public virtual ActionResult Twitter(string user, string pass) { bool success = _authenticate.Login(user, pass); } // login with fb public virtual ActionResult Facebook(string user, string pass) { bool success = _authenticate.Login(user, pass); } // login with google public virtual ActionResult Google(string user, string pass) { bool success = _authenticate.Login(user, pass); }
统一将如何确切地知道针对不同类型的身份验证必须解决的对象?在这种情况下,我该如何进行条件解析?
我和我的一个朋友交谈,他解释了这种情况是否是错误的设计,但这只是出厂模式。
解决此问题的一种简单方法是使用策略模式。请注意,您可以添加或删除登录提供程序而无需更改设计- 您只需要更改DI配置即可。
public interface IAuthenticate{ bool Login(string user, string pass); bool AppliesTo(string providerName); } public interface IAuthenticateStrategy { bool Login(string providerName, string user, string pass); }
public class TwitterAuth : IAuthenticate { bool Login(string user, string pass) { //connect to twitter api } bool AppliesTo(string providerName) { // I used the type name for this example, but // note that you could use any string or other // datatype to select the correct provider. return this.GetType().Name.Equals(providerName); } } public class FacebookAuth: IAuthenticate { bool Login(string user, string pass) { //connect to fb api } bool AppliesTo(string providerName) { return this.GetType().Name.Equals(providerName); } }
public class AuthenticateStrategy: IAuthenticateStrategy { private readonly IAuthenticate[] authenticateProviders; public AuthenticateStrategy(IAuthenticate[] authenticateProviders) { if (authenticateProviders == null) throw new ArgumentNullException("authenticateProviders"); this.authenticateProviders = authenticateProviders; } public bool Login(string providerName, string user, string pass) { var provider = this.authenticateProviders .FirstOrDefault(x => x.AppliesTo(providerName)); if (provider == null) { throw new Exception("Login provider not registered"); } return provider.Login(user, pass); } }
// Note that the strings used here for instance names have nothing // to do with the strings used to select the instance in the strategy pattern unityContainer.RegisterType<IAuthenticate, TwitterAuth>("twitterAuth"); unityContainer.RegisterType<IAuthenticate, FacebookAuth>("facebookAuth"); unityContainer.RegisterType<IAuthenticateStrategy, AuthenticateStrategy>( new InjectionConstructor( new ResolvedArrayParameter<IAuthenticate>( new ResolvedParameter<IAuthenticate>("twitterAuth") ), new ResolvedArrayParameter<IAuthenticate>( new ResolvedParameter<IAuthenticate>("facebookAuth") ) ));
private readonly IAuthenticateStrategy _authenticateStrategy; public AuthenticateController(IAuthenticateStrategy authenticateStrategy) { if (authenticateStrategy == null) throw new ArgumentNullException("authenticateStrategy"); _authenticateStrategy = authenticateStrategy; } // login with twitter public virtual ActionResult Twitter(string user, string pass) { bool success = _authenticateStrategy.Login("TwitterAuth", user, pass); } // login with fb public virtual ActionResult Facebook(string user, string pass) { bool success = _authenticateStrategy.Login("FacebookAuth", user, pass); }