Scrittura 'interfacce' per classi statiche

5

Sto scrivendo una libreria di convalida del codice postale, in modo da poter chiamare un metodo di supporto

var result = Postcode.IsValid(postcode, country)

A tal fine ho bisogno di avere "classi" che rappresentino i paesi supportati e sappiano come convalidarli. Al momento ho un'interfaccia così:

public interface IPostcode {
    bool IsValid(string postcode);
}

e devo avere classi per ogni paese, ad es.

public class USA : IPostcode {
  public bool IsValid(string postcode) {
     // ... validate here
  }

Il metodo di supporto seleziona il IPostcode relativo in base al codice paese.

Il problema è che sembra sbagliato dover istanziare classi prive di stato o proprietà, solo metodi che sarebbero di gran lunga migliori se fossero static . Ma ovviamente le classi statiche non possono avere interfacce. C'è un modello migliore per questo?

    
posta Quango 30.01.2018 - 12:05
fonte

3 risposte

5

Non penso che ci sia qualcosa di sbagliato nell'avere classi senza stato. Finché le classi hanno un comportamento diverso (diversa logica di validazione del codice postale) sono giustificate.

Potresti poter avere lo stesso risultato con metodi statici e usare una firma delegata piuttosto che un'interfaccia (poiché l'interfaccia è comunque una singola firma di funzione), ma penso che l'uso delle classi sia più naturale e diretto.

    
risposta data 30.01.2018 - 12:29
fonte
2

Il punto di un'interfaccia è consentire a più implementazioni di esporre lo stesso contratto di funzionalità.

Sebbene la tua implementazione di IPostCode possa non avere stato, e quindi sei tentato di farla rispettare rendendo il metodo statico. Potrei avere un'implementazione che colpisce un database e ha bisogno della stringa di connessione o di qualsiasi altra cosa.

Puoi ancora avvolgere un metodo statico se devi

USA : IPostcode
{
    private static bool isValid(string postcode) {...}
    public bool IsValid(string postcode)
    {
        return isValid(postcode);
    }
}

Inietta un Func che può essere dichiarato staticamente altrove

USA : IPostcode
{
    public USA(Func<string, bool> postcodeValidator) {...}
    public bool IsValid(string postcode)
    {
        return postcodeValidator(postcode);
    }
}

Ma non buttare via l'interfaccia IPostCode, in quanto ha numerosi vantaggi, consentendo l'utilizzo di altre implementazioni, specialmente nei test. Dove potresti voler sostituire la convalida standard con un manichino

MockCountry : IPostcode
{
    public bool IsValid(string postcode)
    {
         return true;
    }
}

Il che sarebbe quasi impossibile con solo statica

    
risposta data 30.01.2018 - 13:28
fonte
0

Il seguente suggerimento dovrebbe essere utilizzato solo se i singoli validatori di paese non eseguono, ad esempio, il recupero dei dati da un database in fase di runtime, vale a dire solo l'accesso ai dati immutabili.

Supponendo che lo facciano, la soluzione più semplice qui è quella di abbandonare l'idea del polimorfismo attraverso le implementazioni dell'interfaccia e di passare invece ad usare un dizionario di funzioni:

public static class Postcode
{
    private static readonly Dictionary<string, Func<string, bool>> Validators = 
        new Dictionary<string, Func<string, bool>>
        {
            ["USA"] : USAPostcode.IsValid,
            ["UK"] : UKPostcode.IsValid,
            ...
        };

    public static bool IsValid(string postcode, string country) =>
        Validators.TryGetValue(country, out var validator) 
        ? validator(postcode) 
        : throw new ArgumentException("No such country", nameof(country));
}

Le classi statiche non supportano le interfacce, ma i metodi statici sono idealmente progettati per essere utilizzati con Func<> delegati. Quindi "li scandaglia" in questo modo.

Ricorda: non utilizzare metodi statici per l'accesso o la modifica dello stato , ad esempio il recupero dei dati da un database in fase di runtime. Quindi usa questo modello solo se il set di validatori e le loro regole sono immutabili.

    
risposta data 30.01.2018 - 13:21
fonte

Leggi altre domande sui tag