Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 面向对象的用户输入验证设计_Java_Oop_Coding Style - Fatal编程技术网

Java 面向对象的用户输入验证设计

Java 面向对象的用户输入验证设计,java,oop,coding-style,Java,Oop,Coding Style,目前,我试图在设计一些东西时考虑OO原则。比如说,在处理用户输入之前,我需要验证它。根据OO,单独的验证器类将是正确的方法。这将如下所示: public class Validator{ public void validate(String input) throws ValidationException{ if (input.equals("")) throw new ValidationException("Input was empty");

目前,我试图在设计一些东西时考虑OO原则。比如说,在处理用户输入之前,我需要验证它。根据OO,单独的验证器类将是正确的方法。这将如下所示:

    public class Validator{
      public void validate(String input) throws ValidationException{
        if (input.equals("")) throw new ValidationException("Input was empty");
      }
    }
然后,我的处理类(之前通过依赖项注入获得了validator对象)将调用
validator.validate(input)

这种设计的一个优点是

  • 我的处理类可以通过DI获得验证器的模拟,这使得测试更容易
  • 验证器类可以独立测试
  • 然而,我的疑问在于验证器的设计。根据OO,它缺少某种状态。在这种设计中,它是一个util类,验证方法可以是
    static
    。我也读过很多次(静态)Util类是糟糕的OO设计。那么,在保留我提到的两个优点的同时,如何使用更多的OO来实现这一点呢


    PS:也许,OO只是解决这类问题的一个糟糕的方法。但是,我希望看到OO解决方案的样子,并形成我自己的观点。

    您示例中的验证程序没有状态(也不需要任何状态),但另一个验证程序可能需要状态(比如使用格式):

    例如:

    public class RegExValidator {
        private Pattern pattern;
    
        public RegExValidator(String re) {
            pattern = Pattern.compile(re);
        }
    
        public void validate(String input) throws ValidationException {
            if (!pattern.matcher(input).matches()) {
                throw new ValidationException("Invalid syntax [" + input + "]");
            }
        }
    }
    

    关注问题的OOP方面(而不是异常是否是处理验证的正确方法):

    为什么只有一个验证器

    interface Validator<T> {
        void validate(T toValidate) throws ValidationException;
    }
    
    你可以很容易地测试它。 事实上,如果您使用Java 8,这将是一个功能接口,因此单个实用程序类可以承载多个验证器:

    class ValidationUtil {
        public static void emptyString(String val) // same code as above
    }
    
    ValidationUtil::emptyString
    将实现
    Validator
    。 您可以将多个验证器与一个复合模式相结合

    如果你需要的话,你也可以有一个带有状态的验证器

    class ListIsSortedValidator implements Validator<Integer> {
        private int lastInt = Integer.MIN_VALUE;
        public void validate(Integer val) throw ValidationException {
            if (val < lastInt) throw new ValidationException("not sorted");
            lastInt = val;
        }
    }
    
    类ListIsSortedValidator实现验证器{
    private int lastInt=Integer.MIN_值;
    公共void validate(整数val)抛出ValidationException{
    如果(val
    例如,您可以使用它来验证列表:

    List<Integer> list = createList();
    Validator<Integer> validator = new ListIsSortedValidator();
    list.forEach(validator::validate);
    
    List List=createList();
    Validator Validator=新的ListIsSortedValidator();
    list.forEach(validator::validate);
    
    当然这取决于具体情况,但我认为你的直觉是正确的。这种设计可以更加面向对象

    不仅仅是
    验证器
    没有状态,这是一个纯粹的机械指标,表明它可能不是一个正确的抽象,而且名称本身告诉我们一些事情。通常,
    Validator
    (甚至
    EmptyStringValidator
    )不是问题域的一部分。当你必须创造一些纯技术性的东西时,这总是一个坏兆头(尽管有时这是两害相权取其轻)

    我假设您不是在编写web框架,而是在尝试编写具有某个域的应用程序。例如,它有用户注册。然后,
    RegistrationForm
    是问题域的一部分。用户知道“登记表”,你可以谈论它,他们会知道你的意思

    在这种情况下,面向对象的验证解决方案是,该对象负责在自身“提交”期间对自身进行验证

    public final class注册表单扩展表单{
    ...
    @凌驾
    公开作废提交(){
    //在这里进行验证
    //如果出现问题,请将输入字段设置为错误
    //如果一切都好,就做逻辑
    }
    }
    
    我知道这不是web框架通常看到或支持的解决方案。但这就是面向对象解决方案的样子

    要始终牢记的两个要点是:

  • 不要从对象“获取”数据,而是让他们做一些事情。这和其他任何东西一样适用于UI代码
  • 当对象关注有意义的事物时,OO是有意义的,例如问题域。避免过度表示技术(不重要)对象,如
    验证器
    (如果这不是应用程序的域)

  • 我认为最好将所有验证错误写入集合并返回。然后,您可以根据需要处理错误(异常、正确的html页面、json响应等)。假设用户必须用10个字段填写某个表单-您的设计将在第一个字段上引发异常,而不会告诉其他9个字段。所以您的验证器只用于检查数据并返回结果,其他类将编写响应。您是对的,我以前没有考虑过这一点。
    List<Integer> list = createList();
    Validator<Integer> validator = new ListIsSortedValidator();
    list.forEach(validator::validate);