2010-04-05 10 views
8

Tengo algunas clases en mi proyecto actual donde la validación de direcciones de correo electrónico/sitio web es necesaria. Los métodos para hacer eso son todos iguales.clases múltiples con los mismos métodos - mejor patrón

Me pregunto cuál es la mejor manera de implementar esto, así que no necesito tener estos métodos copiar pegado en todas partes?

Las clases en sí mismas no están necesariamente relacionadas, solo tienen esos métodos de validación en común.

+0

¿Qué más hacen las clases? En aras de la claridad, una clase debería tener un único propósito. La solución de FrustratedWithFormsDes sigue este principio. – outis

Respuesta

15

¿Qué le parece agregar una interfaz y usar un método de extensión?

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 */ } 
} 

De esa manera:

  • ninguna herencia innecesaria
  • hay duplicación
+0

Dentro de la clase A, ¿puedo ahora acceder al método Bar? –

+0

Sí, var aClass = new A(); aClass.Bar(); –

+2

parece un abuso de método de extensión para mí. ¿Por qué necesita todas las clases que necesitan validación de correo electrónico para implementar alguna interfaz (vacía) y hacer magia de método de extensión si pudieran simplemente llamar a un método estático de una clase EmailUtils (o crear un objeto EmailValidator y llamar al método Validate? en eso)? también parece que solo necesita el código de validación de correo electrónico dentro de las clases, que no debería requerir la implementación de una interfaz. – stmax

7

Es posible que desee poner todo el código de validación en una clase Validator, luego use esa clase en cualquier lugar donde se necesite validación. El acceso a la validación debe hacerse a través de un único método, Validate(object Something) tal vez. Creo que esto se llama "Composición" (en lo que respecta a los patrones de diseño).

Más adelante, puede tener subclases de Validator que quizás sean más específicas o hagan diferentes tipos de validación.

También podría tener todas las clases que requieren validación extender una clase base o clase abstracta que tiene el 90% de la validación en el mismo.

+1

El mejor término es "Asociación", que es una relación de clase (http://en.wikipedia.org/wiki/Class_diagram#Instance_Level_Relationships) en lugar de un patrón. En cuanto a los patrones, el patrón de estrategia (http://en.wikipedia.org/wiki/Strategy_pattern) podría estar involucrado. – outis

0

crear clases e interfaces lógicas de validación, y les han de ser inyectados en el código de manera independiente ... la lógica de la validación para que se pueda reutilizar ...

1

Crear un Utilit y clase y define estos métodos como métodos de extensión para la clase/interfaces apropiadas.

2

Sí, duplicar este código sería un mal olor, puede extraer estos métodos a una sola clase Helper en métodos estáticos o puede definir una clase de interfaz "Validator" y utilizando esta interfaz, puede vincular diferentes métodos de validación con cadena del patrón de responsabilidad.

5

Suena como que sólo tiene una clase estática con un método estático

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

+1 por simplicidad en lugar del mal uso del método de extensión. – stmax

+1

+1 La clase de utilidades parece ser el camino a seguir aquí. Tener una clase de utilidad con métodos estáticos que validen el correo electrónico, verifiquen las direcciones web y otro tipo de validaciones. Y llame a esta Utilidad métodos estáticos cada vez que necesite esos métodos. –

0

Crear Email como una clase separada.
Use Email como propiedades/parámetros/valores devueltos en sus clases en lugar de String.
Crea EmailValidator para validar cadenas como direcciones de correo electrónico.
Crea EmailFactory que devuelve el correo electrónico cuando pasa una dirección de correo electrónico válida y nulo si no.

(Haga lo mismo para el sitio web).

1

Realmente necesita echar un vistazo a la metodología de programación orientada a aspectos (AoP). Enterprise Library 4.1 tiene una implementación de AoP llamada Unity Interception.

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

Este marco le permite codificar una sola clase de controlador para la validación de correo electrónico. Entonces, lo que esto implica es que el código de validación entra en una clase de controlador y ya no es parte de la clase (es). Lo siguiente que haces es marcar las clases para la intercepción.

Puede interceptar las clases de varias formas, incluida la configuración de un atributo en el método deseado que debe ser interceptado y gestionado según sus requisitos. Establecer un atributo es probablemente la forma más fácil de hacer una intercepción.

0

Recomiendo crear una interfaz IValidator y luego crear múltiples validadores diferentes que manejen diferentes escenarios. Aquí está un ejemplo:

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

El método CanValidateType() podría ser un poco más complejo, pero espero que se entiende la idea. Básicamente identifica si el validador puede manejar la entrada suministrada. Aquí hay un par de implementaciones:

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 */ 
    } 
} 

Ahora que va a utilizar la inyección de constructor para inyectar la dependencia en su clase:

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 */ 
    } 
} 

El CanValidateType es muy útil cuando se tiene una clase que puede utilizar varios validadores. En este escenario, transfiere una lista o una matriz de validadores al constructor.

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

A continuación, tendría que pasar en la instancia requerida del validador (s) a sus clases de alguna manera. Esto se hace a menudo con un contenedor IoC (como Castle Windsor) o hágalo usted mismo.

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

El código anterior se vuelve tedioso a hacer por su cuenta, es por eso que los contenedores IoC son tan práctico. Con un contenedor IoC que puede hacer algo como lo siguiente:

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

Todo el mapeo de interfaces se realiza en el app.config o web.config.

Aquí está an awesome tutorial en Dependency Injection y el contenedor Castle Windsor IoC.

Cuestiones relacionadas