Template method pattern where each implementation requires different arguments?

徘徊边缘 提交于 2019-12-11 03:39:17

问题


I have a base abstract class that needs an algorithm for Authentication. I have two implementations of this, one will hash a password and compare it to a stored hash, the other will use windows active directory.

But before actually doing the hash check or the windows authentication, I have extra workflow logic that must absolutely be implemented. So things like failedPasswordCount, lastAuthenticationAttemptDate, IsUserApproved, etc. must always be modified or used in the same way no matter the algorithm for Authentication.

This problem seems to me like it can be resolved using Template Method Pattern, except that, the information required to implement my two Authentication methods are different depending on which one is used.

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)
    {
         ...
    }
}

What is the best way to solve this problem? Is there another known pattern that already addresses this? Or anyone has a good idea?


回答1:


Assuming your client code knows what to do (what actual parameters should be applied), you can easily introduce a class hierarchy around your authentication, thus making it possible to declare the contract on the base class of such hierarchy.

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



回答2:


You could keep your base interface's "DoAuthenticate()" clean of parameters this way

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

or

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

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

And provide the parameter values to use when you instantiate the User derived object.




回答3:


This is really an example of a Strategy pattern (where is strategy is the authentication/validation mechanism) meets a Composite pattern

Validation is frequently a Composite pattern. When you break it down, you want to separate the what you want to from the how you want to do it, you get:

If foo is valid
then do something.

Here we have the abstraction is valid

I just wrote about, essentially, your case here. If you find this answer to be most awesesome, then give IT a check/vote too :)



来源:https://stackoverflow.com/questions/23503932/template-method-pattern-where-each-implementation-requires-different-arguments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!