multiple classes with same methods - best pattern
I have a few classes in my current project where validation of Email/Website addresses is n开发者_C百科ecessary. The methods to do that are all the same.
I wondered what's the best way to implement this, so I don't need to have these methods copy pasted everywhere?
The classes themselves are not necessarily related, they only have those validation methods in common.
How about adding an interface, and using an extension method?
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 */ }
}
That way:
- no unnecessary inheritance
- no duplication
You might want to put all the validation code into a Validator class, then use that class anywhere that validation is needed. Access to validation should be through a single method, Validate(object Something)
maybe. I think this is called "Composition" (as far as design patterns go).
Later on, you can have sub-classes of Validator that maybe more specific or do different kinds of validation.
You could also have all classes requiring validation extend a base class or abstract class that has 90% of the validation in it.
Sounds like you just need a static class with a static method
public static class Utilities{
public static bool validEmail(string email)
{
//Your code here
}
}
Yes, duplicating this code would be a bad smell, you can extract these methods to single Helper class in static methods or you can define a "Validator" interface class and using this interface, you can link different validation methods with chain of responsibility pattern.
Create a Utility class and define these methods as extension methods for appropriate class/interfaces.
You really need to take a good look at the aspect oriented programming methodology (AoP). The Enterprise Library 4.1 has an AoP implementation called Unity Interception.
http://msdn.microsoft.com/en-us/library/dd140045.aspx
This framework allows you to code a single handler class for the email validation. So what this entails is that the validation code goes into a handler class, and no longer part of the class(es). Next thing you do is mark the classes for interception.
You can intercept the classes in a variety of ways, including setting an attribute on the desired method that should be intercepted and handled per your requirements. Setting an attribute is probably the easiest way to do an interception.
create validation logic classes and interfaces, and have them being injected in your code... so seperate the logic from validation so that it can be reused...
Create Email
as a separate class.
Use Email
as properties/parameters/return values in your classes instead of String
.
Create EmailValidator
to validate strings as email addresses.
Create EmailFactory
that returns Email when passed a valid email address and null if not.
(Do same for Website).
I would recommend you create an IValidator interface then create multiple different validators that handle different scenarios. Here's one example:
public interface IValidator {
bool CanValidateType(string type);
bool Validate(string input);
}
The CanValidateType() method could be a bit more complex, but I hope you get the idea. It basically identifies whether the validator can handle the input supplied. Here are a couple implementations:
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 */
}
}
Now you will use constructor injection to inject the dependency into your class:
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 */
}
}
The CanValidateType comes in handy when you have a class that can use multiple validators. In this scenario you pass in a list or an array of validators to the 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;
}
}
You would then have to pass in the required instance of the validator(s) to your classes somehow. This is often done with an IoC container (like Castle Windsor) or do it yourself.
IValidator emailValidator = new EmailValidator();
IValidator urlValidator = new UrlValidator();
SomeSimpleClass simple = new SomeSimpleClass(urlValidator);
SomeComplexClass complex = new SomeComplexClass(new List<IValidator> { emailValidator, urlValidator });
The above code gets tedious to do on your own, this is why IoC containers are so handy. With an IoC container you can do something like the following:
SomeSimpleClass simple = container.Resolve<SomeSimpleClass>();
SomeComplexClass complex = container.Resolve<SomeComplexClass();
All the mapping of interfaces is done in your app.config or web.config.
Here's an awesome tutorial on Dependency Injection and The Castle Windsor IoC container.
精彩评论