Selezione della polizia senza hard coding un'istruzione if

-1

Sto provando a modellare la sicurezza del mio progetto usando DDD ma sono finito in un vicolo cieco.

Ho le classi User , UserA e UserB che sono state modellate come segue. Ciò che cambia in pratica è che gli oggetti UserA hanno una politica di accesso diversa da UserB e per questo ho pensato di utilizzare il pattern STRATEGY come una buona opzione.

public abstract class User
{
    public int UserId { get; set; }
    public string Login { get; set; }
    public string PasswordHash { get; set; }
}

public class UserA : User
{
    // custom UserA properties and methods 
}

public class UserB : User
{
    // custom UserB properties and methods
}

public interface IAccessPolice {}

public class EvenAccessPolice : IAccessPolice
{
    // string just for simplify but it is a Service
    private readonly string _someDependencyInjected;

    public EvenAccessPolice(string someDependencyInjected)
    {
        _someDependencyInjected = someDependencyInjected;
    }

    public bool CanAccess(UserA user)
    {
        // authentication logic for UserA
        return user.UserId % 2 == 0;
    }
}

public class OddAccessPolice : IAccessPolice
{
    public bool CanAccess(UserB user)
    {
        // authentication logic for UserB
        return user.UserId % 2 != 0;
    }
}

public class AuthenticationService
{
    public IList<User> _userRepository = new List<User>();

    public bool CheckIfUserCanLogin(int userId)
    {
        var user = _userRepository.Where(u => u.UserId == userId).FirstOrDefault();

        // this if is annoing me
        if (user is UserA)
        {
            var authPolice = new EvenAccessPolice("Inject this value...");
            return authPolice.CanAccess(user as UserA);
        }
        else
        {
            var authPolice = new OddAccessPolice();
            return authPolice.CanAccess(user as UserB);
        }
    }
}

AuthenticationService ottiene l'istanza utente ( UserA o UserB ) e controlla se l'utente può o meno accedere al sistema. L'istruzione if utilizzata per decidere quale delle politiche deve essere eseguita è un codice che mi sembra strano dal momento che il mio servizio non verrà chiuso quando dovrò aggiungere / modificare le politiche.

Poiché la politica è legata al sottotipo user , ho pensato di inserire una proprietà in UserA e UserB che restituirebbe l'istanza corretta di IAccessPolice , ma che mi obbligherebbe a caricare EvenAccessPolice di dipendenze nella mia entità di dominio, e penso che non sia un'opzione (odore di codice).

C'è un modo per acquisire IAccessPolice da user senza utilizzare un'istruzione if ?

    
posta Douglas Gandini 20.09.2017 - 18:06
fonte

1 risposta

5

Il problema chiave qui è che l'interfaccia della tua politica non ha metodi. Non ha altro scopo se non quello di contrassegnare le classi. Per rendere agevole la politica, è necessario definire il metodo CanAccess nell'interfaccia. Sarebbe come questo:

public interface IAccessPolice
{
    bool CanAccess(User user);
}

Ciò mantiene l'interfaccia uguale per i tuoi criteri pari e dispari, in modo che AuthenticationService non abbia bisogno di conoscere i dettagli dell'istanza. Dopo averlo fatto, puoi utilizzare molte strategie diverse per ottenere il IAccessPolice appropriato per il tuo utente. Un'opzione è di iniettarla nel tuo User :

public abstract class User
{
    public int UserId { get; set; }
    public string Login { get; set; }
    public string PasswordHash { get; set; }
    public IAccessPolice AccessPolice { get; private set; } // readonly
}

Un'altra opzione è che il IAuthenticationService usi un modello predefinito per creare o cercare l'istanza IAccessPolice appropriata:

public class AuthenticationService
{
    // ... all the other stuff

    private IAccessPolice GetAccessPoliceForUser (User user)
    {
        // Create or lookup based on type,
        // or simply pull it from the user instance
        // if you injected it into your user above:

        return user.AccessPolice;
    }
}

In entrambi i casi, semplifica il modo in cui sei interessato a lavorare in questo modo:

public bool CheckIfUserCanLogin(int userId)
{
    var user = _userRepository.Where(u => u.UserId == userId).FirstOrDefault();
    var accessPolice = GetAccessPoliceForUser(user);

    return accessPolice.CanAccess(user);
}
    
risposta data 20.09.2017 - 18:41
fonte

Leggi altre domande sui tag