2010-04-05 12 views
8

Ho alcune classi nel mio progetto corrente in cui è necessaria la convalida degli indirizzi di posta elettronica/sito web. I metodi per farlo sono tutti uguali.più classi con gli stessi metodi - miglior schema

Mi chiedevo qual è il modo migliore per implementare questo, quindi non ho bisogno di copiare questi metodi copiati ovunque?

Le classi stesse non sono necessariamente correlate, hanno solo quei metodi di convalida in comune.

+0

Cos'altro fanno le lezioni? Per motivi di chiarezza, una classe dovrebbe avere un unico scopo. La soluzione di FrustratedWithFormsDes segue questo principio. – outis

risposta

15

Come aggiungere un'interfaccia e utilizzare un metodo di estensione?

public interface IFoo { } 

public class A : IFoo {} 
public class B : IFoo {} 
public class C : IFoo {} 

public static class FooUtils { 
    public static void Bar(this IFoo foo) { /* impl */ } 
} 

questo modo:

  • alcuna eredità inutili
  • alcuna duplicazione
+0

All'interno della classe A, ora posso accedere al metodo Bar? –

+0

Yep var aClass = new A(); aClass.Bar(); –

+2

mi sembra un metodo di abuso. perché avevi bisogno di tutte le classi che necessitavano di convalida dell'email per implementare alcune interfacce (vuote) e applicare qualche metodo di estensione magica se invece potessero semplicemente chiamare un metodo statico di una classe EmailUtils (o creare un oggetto EmailValidator e chiamare il metodo Validate su di essa)? inoltre sembra che abbia solo bisogno del codice di convalida dell'email all'interno delle classi - che non dovrebbe richiedere l'implementazione di un'interfaccia. – stmax

7

Si consiglia di inserire tutto il codice di convalida in una classe Validator, quindi utilizzare tale classe ovunque sia necessaria la convalida. L'accesso alla convalida dovrebbe avvenire attraverso un singolo metodo, Validate(object Something). Penso che questo si chiami "Composition" (per quanto riguarda i design pattern).

In seguito, è possibile avere sottoclassi di Validator che potrebbero essere più specifici o fare diversi tipi di convalida.

È inoltre possibile che tutte le classi che richiedono la convalida estendano una classe base o una classe astratta che contiene il 90% della convalida.

+1

Il termine migliore è "Associazione", che è una relazione di classe (http://en.wikipedia.org/wiki/Class_diagram#Instance_Level_Relationships) piuttosto che uno schema. Per quanto riguarda i pattern, potrebbe essere coinvolto il modello di strategia (http://en.wikipedia.org/wiki/Strategy_pattern). – outis

0

creare classi logica di convalida e interfacce, e li hanno essere iniettato nel codice ... in modo separato la logica dalla convalida in modo che possa essere riutilizzata ...

1

Creare un Utilit y classe e definire questi metodi come metodi di estensione per appropriate classi/interfacce.

2

Sì, la duplicazione di questo codice sarebbe un cattivo odore, è possibile estrarre questi metodi su una singola classe Helper in metodi statici oppure è possibile definire una classe di interfaccia "Validator" e utilizzando questa interfaccia, è possibile collegare diversi metodi di convalida con catena modello di responsabilità.

5

Suona come avete solo bisogno di una classe statica con un metodo statico

public static class Utilities{ 
    public static bool validEmail(string email) 
    { 
     //Your code here 
    } 
} 
+1

+1 per semplicità invece di uso improprio del metodo di estensione. – stmax

+1

+1 Le classi di utilità sembrano il modo per andare qui. Avere una classe di utilità con metodi statici che convalida la posta elettronica, controllare gli indirizzi Web e altri tipi di convalida. E chiama questo metodo statico di Utilità ogni volta che hai bisogno di questi metodi. –

0

Creare Email come una classe separata.
Utilizzare Email come proprietà/parametri/valori di ritorno nelle classi invece di String.
Creare EmailValidator per convalidare le stringhe come indirizzi di posta elettronica.
Creare EmailFactory che restituisce Email quando viene passato un indirizzo email valido e null se non.

(Fare lo stesso per il sito Web).

1

È davvero necessario dare un'occhiata alla metodologia di programmazione orientata all'aspetto (AoP). Enterprise Library 4.1 ha un'implementazione AoP chiamata Unity Interception.

http://msdn.microsoft.com/en-us/library/dd140045.aspx

Questo quadro permette di codificare una singola classe gestore per la convalida e-mail. Quindi, ciò che questo comporta è che il codice di convalida entri in una classe di gestori e non faccia più parte della classe o delle classi. La prossima cosa che fai è segnare le classi per l'intercettazione.

È possibile intercettare le classi in vari modi, tra cui l'impostazione di un attributo sul metodo desiderato che deve essere intercettato e gestito in base alle proprie esigenze. Impostare un attributo è probabilmente il modo più semplice per fare un'intercettazione.

0

Si consiglia di creare un'interfaccia IValidator quindi creare più validatori diversi che gestiscono diversi scenari. Ecco un esempio:

public interface IValidator { 
    bool CanValidateType(string type); 
    bool Validate(string input); 
} 

Il metodo CanValidateType() potrebbe essere un po 'più complesso, ma spero che si ottiene l'idea. In pratica identifica se il validatore può gestire l'input fornito. Qui ci sono un paio di implementazioni:

public class UrlValidator : IValidator { 
    bool CanValidateType(string type) { 
     return type.ToLower() == "url"; 
    } 

    bool Validate(string input) { 
     /* Validate Url */ 
    } 
} 

public class EmailValidator : IValidator { 
    bool CanValidateType(string type) { 
     return type.ToLower() == "email"; 
    } 

    bool Validate(string input) { 
     /* Validate Email */ 
    } 
} 

Ora si userà l'iniezione del costruttore per iniettare la dipendenza nella tua classe:

public class SomeSimpleClass { 
    private IValidator validator; 

    public SomeComplexClass(IValidator validator) { 
     this.validator = validator; 
    } 

    public void DoSomething(string url) { 
     if (validator.CanValidateType("url") && 
      validator.Validate(url)) 
      /* Do something */ 
    } 
} 

Il CanValidateType è particolarmente utile quando si dispone di una classe che può utilizzare più validatori. In questo scenario si passa in una lista o una matrice di validatori al costruttore.

public class SomeComplexClass { 
    private List<IValidator> validators; 

    public SomeComplexClass (List<IValidator> validators) { 
     this.validators = validators; 
    } 

    public bool ValidateUrl(string url) { 
     foreach (IValidator validator in this.validators) 
      if (validator.CanValidateType("url")) 
       return validator.Validate(url); 
     return false; 
    } 


    public bool ValidateEmail(string email) { 
     foreach (IValidator validator in this.validators) 
      if (validator.CanValidateType("email")) 
       return validator.Validate(email); 
     return false; 
    } 
} 

Si sarebbe quindi dovuto passare l'istanza richiesta del validatore (s) per le vostre classi in qualche modo. Questo è spesso fatto con un contenitore IoC (come Castle Windsor) o fai da te.

IValidator emailValidator = new EmailValidator(); 
IValidator urlValidator = new UrlValidator(); 
SomeSimpleClass simple = new SomeSimpleClass(urlValidator); 
SomeComplexClass complex = new SomeComplexClass(new List<IValidator> { emailValidator, urlValidator }); 

Il codice di cui sopra diventa noioso da fare da soli, questo è il motivo per cui i contenitori IoC sono così a portata di mano. Con un contenitore CIO si può fare qualcosa di simile al seguente:

SomeSimpleClass simple = container.Resolve<SomeSimpleClass>(); 
SomeComplexClass complex = container.Resolve<SomeComplexClass(); 

Tutta la mappatura delle interfacce è fatto nel vostro app.config o web.config.

Ecco an awesome tutorial su Dipendenza dell'iniezione e il contenitore Windsor Castle IoC.

Problemi correlati