【问题标题】:multiple classes with same methods - best pattern具有相同方法的多个类 - 最佳模式
【发布时间】:2010-04-05 13:23:15
【问题描述】:

我目前的项目中有一些课程需要验证电子邮件/网站地址。这样做的方法都是一样的。

我想知道实现这一点的最佳方法是什么,所以我不需要将这些方法复制粘贴到任何地方?

类本身不一定相关,它们只有那些共同的验证方法。

【问题讨论】:

  • 这些课程还有什么作用?为了清楚起见,一个类应该有一个单一的目的。 FrustratedWithFormsDes 的解决方案就是遵循这个原则。

标签: c# function class design-patterns


【解决方案1】:

添加一个接口,使用扩展方法怎么样?

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

这样:

  • 没有不必要的继承
  • 没有重复

【讨论】:

  • 在A类中,我现在可以访问方法Bar了吗?
  • 是的 var aClass = new A(); aClass.Bar();
  • 对我来说看起来像是滥用扩展方法。如果他们可以简单地调用 EmailUtils 类的静态方法(或创建一个 EmailValidator 对象并调用 Validate 方法,为什么你需要所有需要电子邮件验证的类来实现一些(空)接口并对其进行一些扩展方法魔术?在上面)?似乎他只需要类中的电子邮件验证代码 - 这不应该需要实现接口。
  • 这肯定是对接口和扩展方法的不好使用。很可怕,它获得了最多的选票并被标记为答案。
  • 这听起来像是一种“利用”来克服 C# 中缺乏多类继承的问题。这在概念上听起来可能是错误的,但结果与从“Foo”类继承并使用它自己的“Bar”实现相同。当您还必须从另一个类继承时,问题就来了,这就是 Marc 的解决方案的由来。
【解决方案2】:

您可能希望将所有验证代码放入 Validator 类中,然后在需要验证的任何地方使用该类。访问验证应该通过单一方法,Validate(object Something) 可能。我认为这被称为“组合”(就设计模式而言)。

稍后,您可以拥有可能更具体或执行不同类型验证的 Validator 子类。

您还可以让所有需要验证的类扩展一个包含 90% 验证的基类或抽象类。

【讨论】:

【解决方案3】:

听起来你只需要一个带有静态方法的静态类

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

【讨论】:

  • +1 实用程序类似乎是去这里的方式。有一个带有静态方法的 Utility 类,用于验证电子邮件、检查网址和其他类型的验证。并在您需要这些方法时调用此实用程序静态方法。
【解决方案4】:

是的,复制这段代码会很臭,您可以将这些方法提取到静态方法中的单个 Helper 类中,或者您可以定义一个“Validator”接口类并使用此接口,您可以将不同的验证方法与链责任模式。

【讨论】:

    【解决方案5】:

    创建一个实用程序类并将这些方法定义为适当类/接口的扩展方法。

    【讨论】:

      【解决方案6】:

      您确实需要好好看看面向方面的编程方法 (AoP)。 Enterprise Library 4.1 有一个称为 Unity Interception 的 AoP 实现。

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

      此框架允许您为电子邮件验证编写单个处理程序类。所以这意味着验证代码进入处理程序类,不再是类的一部分。接下来要做的是标记要拦截的类。

      您可以通过多种方式拦截类,包括在所需方法上设置一个属性,该方法应根据您的要求进行拦截和处理。设置属性可能是进行拦截的最简单方法。

      【讨论】:

        【解决方案7】:

        创建验证逻辑类和接口,并将它们注入您的代码中...因此将逻辑与验证分开,以便可以重复使用...

        【讨论】:

          【解决方案8】:

          Email 创建为单独的类。
          在您的类中使用Email 作为属性/参数/返回值,而不是String
          创建 EmailValidator 以验证字符串是否为电子邮件地址。
          创建EmailFactory,它在传递有效电子邮件地址时返回电子邮件,如果不是,则返回 null。

          (对网站做同样的事情)。

          【讨论】:

            【解决方案9】:

            我建议您创建一个 IValidator 接口,然后创建多个不同的验证器来处理不同的场景。这是一个例子:

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

            CanValidateType() 方法可能有点复杂,但我希望你明白这一点。它基本上确定验证器是否可以处理提供的输入。以下是几个实现:

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

            现在您将使用构造函数注入将依赖项注入到您的类中:

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

            当您有一个可以使用多个验证器的类时,CanValidateType 会派上用场。在这种情况下,您将一个列表或一组验证器传递给构造函数。

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

            然后,您必须以某种方式将所需的验证器实例传递给您的类。这通常使用 IoC 容器(如 Castle Windsor)或自己完成。

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

            上面的代码自己做会很乏味,这就是 IoC 容器如此方便的原因。使用 IoC 容器,您可以执行以下操作:

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

            所有接口的映射都在你的 app.config 或 web.config 中完成。

            这里是 an awesome tutorial 依赖注入和温莎城堡 IoC 容器。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-07-24
              • 2017-11-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多