12

Условное разрешение - это последнее, чего я не понимаю на данный момент.Единство единства взыскания - Условное разрешение

Допустим, у нас есть интерфейс IAuthenticate:

public interface IAuthenticate{ 
    bool Login(string user, string pass); 
} 

Теперь у меня есть два типа аутентификации.

Twitter Auth

public class TwitterAuth : IAuthenticate 
{ 
    bool Login(string user, string pass) 
{ 
    //connect to twitter api 
} 

} 

Facebook Auth

public class FacebookAuth: IAuthenticate 
{ 
    bool Login(string user, string pass) 
{ 
    //connect to fb api 
} 

} 

регистрирующие типов в единстве конфигурации:

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

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

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

+0

Возможно, ваш друг может быть прав. Посмотрите внимательно, если вы не нарушаете [Принцип замены Лискова] (https://en.wikipedia.org/wiki/Liskov_substitution_principle).Если реализации IAuthenticate не являются взаимозаменяемыми друг для друга (что означает, что потребитель, такой как «AuthenticateController», не будет работать правильно, если он ошибочно реализуется), вы нарушаете LSP. Решение в этом случае часто дает каждой реализации собственную абстракцию. – Steven

ответ

32

Простой способ решить это с помощью strategy pattern. Обратите внимание, что вы можете добавлять или удалять поставщиков регистрации без изменения дизайна - вам просто нужно изменить конфигурацию 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); 
} 

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

Unity Регистрация

// 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); 
} 
3

Unity не будет без вашей помощи. Вы можете указать имя при регистрации типов IAuthenticate:

unityContainer.RegisterType<IAuthenticate, TwitterAuth>("Twitter"); 
unityContainer.RegisterType<IAuthenticate, FacebookAuth>("Facebook"); 

Вы больше не хотите, чтобы непосредственно вводить экземпляр IAuthenticate в свой AuthenticateController. Вы либо получить экземпляр вы хотите на основе условия прямо из единицы:

myContainer.Resolve<IAuthenticate>("Twitter"); 

или вы впрыснуть завод, который делает это для вас (если вам нравится строгий стиль DI).

Смежные вопросы