2010-04-05 17 views
8

Ich habe ein paar Klassen in meinem aktuellen Projekt, wo Validierung von E-Mail/Website-Adressen notwendig ist. Die Methoden dafür sind alle gleich.mehrere Klassen mit den gleichen Methoden - beste Muster

Ich fragte mich, was ist der beste Weg, dies zu implementieren, so dass ich diese Methoden nicht kopieren müssen überall kopieren müssen?

Die Klassen selbst sind nicht unbedingt miteinander verwandt, sie haben nur diese Validierungsmethoden gemeinsam.

+0

Was machen die Klassen sonst noch? Aus Gründen der Klarheit sollte eine Klasse einen einzigen Zweck haben. Die Lösung von FrustratedWithFormsDes folgt diesem Prinzip. – outis

Antwort

15

Wie wäre es mit dem Hinzufügen einer Schnittstelle und einer Erweiterungsmethode?

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

Auf diese Weise:

  • keine unnötige Erbschaft
  • keine Duplizierung
+0

In Klasse A, kann ich jetzt auf die Methode Bar zugreifen? –

+0

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

+2

sieht für mich wie Erweiterungsmethode Missbrauch aus. Warum benötigen Sie alle Klassen, die eine E-Mail-Validierung benötigen, um eine (leere) Schnittstelle zu implementieren und einige Erweiterungsmechanismen anzuwenden, wenn sie stattdessen einfach eine statische Methode einer EmailUtils-Klasse aufrufen (oder ein EmailValidator-Objekt erstellen und die Validate-Methode aufrufen) drauf)? es scheint auch, als ob er nur den Email-Validierungscode innerhalb der Klassen benötigt - das sollte nicht die Implementierung einer Schnittstelle erfordern. – stmax

7

Sie könnten den gesamten Validierungscode in eine Validator-Klasse einfügen und diese Klasse dann überall dort verwenden, wo eine Validierung erforderlich ist. Der Zugriff auf die Validierung sollte über eine einzige Methode erfolgen, Validate(object Something) vielleicht. Ich denke, das nennt man "Composition" (was Designmuster betrifft).

Später können Sie Unterklassen von Validator haben, die möglicherweise spezifischer sind oder verschiedene Arten der Validierung durchführen.

Sie könnten auch alle Klassen, die eine Validierung erfordern, eine Basisklasse oder abstrakte Klasse mit 90% der Validierung darin erweitern lassen.

+1

Der beste Begriff ist "Association", das ist eine Klassenbeziehung (http://en.wikipedia.org/wiki/Class_diagram#Instance_Level_Relationships) anstatt ein Muster. Was Muster betrifft, könnte das Strategiemuster (http://en.wikipedia.org/wiki/Strategy_pattern) beteiligt sein. – outis

0

Validierungslogik Klassen und Schnittstellen erstellen, und haben sie in Ihrem Code injiziert werden ... so seperate die Logik aus der Validierung, so dass sie wiederverwendet werden kann ...

1

Erstellen Sie eine Utilit y-Klasse und definieren Sie diese Methoden als Erweiterungsmethoden für geeignete Klassen/Interfaces.

2

Ja, duplizieren diesen Code wäre ein schlechter Geruch, können Sie diese Methoden zu einzelnen Helper-Klasse in statischen Methoden extrahieren oder Sie können eine "Validator" -Schnittstellenklasse definieren und diese Schnittstelle verwenden, können Sie verschiedene Validierungsmethoden mit Kette verknüpfen des Verantwortungsmusters.

5

Klingt wie Sie nur eine statische Klasse mit einer statischen Methode müssen

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

+1 für die Einfachheit anstelle der Erweiterung Methode Missbrauch. – stmax

+1

+1 Utility-Klasse scheint der Weg zu sein, hier zu gehen. Halten Sie eine Utility-Klasse mit statischen Methoden bereit, die E-Mails validieren, Webadressen und andere Arten von Validierungen prüfen. Und nennen Sie dieses Dienstprogramm statische Methoden, wann immer Sie diese Methoden benötigen. –

0

Email als eigene Klasse erstellen.
Verwenden Sie Email als Eigenschaften/Parameter/Rückgabewerte in Ihren Klassen statt String.
Erstellen Sie EmailValidator, um Zeichenfolgen als E-Mail-Adressen zu validieren.
Erstellen Sie EmailFactory, die E-Mail zurückgibt, wenn eine gültige E-Mail-Adresse und Null übergeben, wenn nicht.

(Do selbe für Website).

1

Sie müssen sich wirklich die aspektorientierte Programmiermethodik (AoP) ansehen. Die Enterprise Library 4.1 verfügt über eine AoP-Implementierung namens Unity Interception.

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

Dieser Rahmen ermöglicht es Ihnen, eine einzelne Handler-Klasse für die E-Mail-Validierung zu codieren. Was damit verbunden ist, ist, dass der Validierungscode in eine Handler-Klasse und nicht mehr Teil der Klasse (n) gelangt. Als nächstes markieren Sie die Klassen für das Abfangen.

Sie können die Klassen in einer Vielzahl von Möglichkeiten abzufangen, ein Attribut auf die gewünschte Methode einschließlich der Einrichtung, die nach Ihren Wünschen abgefangen und behandelt werden sollte. Das Festlegen eines Attributs ist wahrscheinlich der einfachste Weg, eine Überwachung durchzuführen.

0

Ich würde Ihnen empfehlen, eine IValidator-Schnittstelle zu erstellen und dann mehrere verschiedene Validatoren zu erstellen, die verschiedene Szenarien behandeln. Hier ist ein Beispiel:

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

Die CanValidateType() Methode könnte etwas komplizierter sein, aber ich hoffe, Sie bekommen die Idee. Es gibt im Wesentlichen an, ob der Validierer die gelieferte Eingabe verarbeiten kann. Hier sind ein paar Implementierungen:

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

Jetzt werden Sie Konstruktor Injektion verwenden, um die Abhängigkeit in Ihrer Klasse zu injizieren:

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

Die CanValidateType ist praktisch, wenn Sie eine Klasse, die mehrere Validierer verwenden können. In diesem Szenario übergeben Sie eine Liste oder ein Array von Validatoren an den Konstruktor.

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

Sie müssten dann die erforderliche Instanz der Validator (en) in Ihre Klassen irgendwie übergeben. Dies wird oft mit einem IoC Container (wie Castle Windsor) oder selbst gemacht.

Der obige Code wird mühsam auf eigene Faust zu tun, deshalb sind IoC-Container so praktisch. Mit einem IoC-Container können Sie so etwas wie das folgende tun:

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

Alle die Abbildung von Schnittstellen in Ihrem app.config oder web.config erfolgt.

Hier an awesome tutorial auf Dependency Injection und der Behälter Schloss Windsor IoC.

Verwandte Themen