Шаблонный шаблон, где каждая реализация требует разных аргументов?

У меня есть базовый абстрактный класс, который нуждается в алгоритме для аутентификации. У меня есть две реализации этого: один будет хэшировать пароль и сравнивать его с сохраненным хэшем, другой будет использовать Windows Active Directory.

Но перед тем, как делать проверку хеша или проверку подлинности Windows, у меня есть дополнительная логика рабочего процесса, которая должна быть обязательно реализована. Таким образом, такие вещи, как failedPasswordCount, lastAuthenticationAttemptDate, IsUserApproved и т. Д., Всегда должны изменяться или использоваться одинаково, независимо от алгоритма аутентификации.

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

public abstract class User
{
    public bool Authenticate() // my template method
    {
        lastAuthenticationAttemptDate = DateTime.UtcNow();
        if(IsUserApproved)
        {
            if(DoAuthenticate()) // implemented by childs
            {
                return true;
            }
            else
            {
                failedPasswordCount++;
                return false;
            }
        }
    }

    public abstract DoAuthenticate();
}

public UserWindowsLogon : User
{
    public override bool DoAuthenticate(string windowsDomain, string password)
    {
         ...
    }
}

public UserApplicationLogon : User
{
    public override bool DoAuthenticate(string password)
    {
         ...
    }
}

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

3 ответа

Решение

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

public abstract DoAuthenticate( AuthenticationContext context );
...

public UserWindowsLogon : User
{
  public override bool DoAuthenticate( AuthenticationContext context )
  { 
     if ( context is UserWindowsAuthenticationContext )
     {
        // proceed
     }
  }
}

public UserApplicationLogon : User
{
  public override bool DoAuthenticate( AuthenticationContext context )
  {
     if ( context is UserAplicationAuthenticationContext )
     {
        // proceed
     }
   } 
}

public abstract class AuthenticationContext { }

public class UserWindowsAuthenticationContext : AuthenticationContext
{
   public string windowsDomain;
   public string password;
}

public class UserApplicationAuthenticationContext : AuthenticationContext
{
   public string password;
}

Таким образом, вы можете сохранить DoAuthenticate() вашего базового интерфейса в чистоте от параметров

public UserWindowsLogon : User
{
    public string windowsDomain;
    public string password;
    public override bool DoAuthenticate()
    {
         // Check and use windowsDomain/password values here
    }
}

или же

public UserApplicationLogon : User
{
    public UserApplicationLogon(string password) : base()
    {
         this.password = password;
    }

    private string password;
    public override bool DoAuthenticate()
    {
         // use password value here
    }
}

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

Это действительно пример шаблона "Стратегия" (где "стратегия" - это механизм проверки подлинности / проверки), который соответствует " Составному шаблону".

Проверка часто является составным шаблоном. Когда вы разбиваете это, вы хотите отделить то, что вы хотите, от того, как вы хотите это сделать, вы получите:

If foo is valid
then do something.

Здесь у нас действует абстракция

Я просто написал, по сути, о вашем случае здесь. Если вы находите этот ответ наиболее впечатляющим, то проверьте и проголосуйте за него тоже:)

Другие вопросы по тегам