使用哪种设计模式进行验证?

17

我相信我不是唯一面临这个问题的人,但直到现在我仍然无法找到解决方案。问题如下。

我发布了一个网络服务(我无法控制和更改其中的内容),所有客户端都在使用它。我从网络服务接收请求并获得一个非常复杂的对象,为了举例说明,让我们假设我从网络服务调用中接收到一个名为Object A的对象,其中包含其他几个对象,比如对象B、对象C等,而且对象B和对象C还包含一些基本数据类型以及其他对象。我的问题是,我想验证整个Object A(包括所有的子对象和子子对象)。这里推荐使用哪种设计模式?其次,关键点在于我可以从网络服务获取不同类型的Object A。我所说的不同类型的Object A是指Object A取决于客户端,即有些客户端将发送未填充包含在Object B中的数据的Object A,甚至可能部分填充Object B,然后将其发送到Object A中。因此,我必须根据客户端验证Object A(因为某些客户端需要包含对象B,而另一些客户端则不需要,有些客户端需要Object B中的几个元素等)。换句话说,我将有一个存储每个客户端验证规则的地方,这将告诉我客户端ABC想要Object B中的字段abc为字符串类型,最大长度为25个字符,并且该字段必须包含数据。

我想要执行的一些验证如下:

检查某个对象(比如对象B)的字段数据类型、某个字段的长度、该字段是否对于该客户端是必需的或可选的等等...

任何具体的工作示例都将非常有用。

这个特定示例的Object A结构如下。

    public class A
    {
        private B objectB;
        private C objectC;
        // and so on
    }

    public class B{
        private E objectE;
        private String name;
        private int age;
        // and so on
    } 

    public class C
    {
        private F objectF;
        private String address;
        private String country;
    }

    public class E
    {
        // Members here
    }

    public class F
    {
        // Members here
    }

附言:我只是为了普通理解而给类和成员起了任意名称。哦,我忘了提到我在这里使用的是Java,但实际上并不重要,因为设计原则或模式可以适用于任何语言。希望很快能听到你们的回复.. :)


1
验证可以通过多种方式进行,并且非常基于个人观点。请查看策略模式 - Bart
除了策略模式,你能推荐其他的替代方案吗? - Sam ツ
1
我建议您使用Visitor和Factory/AbstractFactory的组合。工厂可以根据客户端类型和特殊规则创建任何验证器类。访问者可以使用验证器类验证整个结构。 - Glauco Cucchiar
2个回答

7

验证是跨领域的关注点。有多种方法和设计模式可以实现。

在Asp.net中,通过属性来实现,在Java Spring中,使用注解来保持代码的清晰、可读性和可维护性。

你可以找到许多不同的方法,需要记住的是这些框架所遵循的方法,即代码维护、可读性和清洁代码。

没有一种万能的解决方案。甚至可以在代码中编写验证。


你在这里提到了一个非常好的观点(我完全忘记了),即验证是一个横切关注点。谢谢。如果我将验证代码编写在我的业务对象或任何对象中,它不会使代码混乱吗?我认为这将违反单一职责原则,你怎么看? - Sam ツ
1
是的,这就是为什么验证是一个横切关注点,就像日志记录一样,有时候你无法避免它。你需要注意的是代码的正确性、清晰易读、不重复和可维护性。 - DarthVader
你能给我推荐一个除了策略模式以外的设计模式吗?我正在尽力保持我的代码整洁、可读、可维护,同时也遵循DRY原则,但我认为我已经到了必须要动手的地步了.. :) - Sam ツ
3
你可以使用装饰者模式。Asp.net 和 Java 框架使用装饰者模式进行验证。 - DarthVader

0
每个类都应该知道如何验证自己。您可以从一个接口(比如IValidatable)派生每个类,该接口具有.Validate()方法。当您在对象A上调用.Validate()时,让它自我验证,然后调用所有子项的.Validate()。这些子项可以以类似的方式自我验证。
我认为这是命令模式的一个非常简单的版本。有点像。
您还可以组合一个验证器,将其附加到您的类上。验证器可以知道如何验证电子邮件地址、常规地址等。这更具可扩展性,因为您基本上正在创建一个工具箱,将其附加到您的类上,其中只包含所需的工具。

3
是的,最初我认为每个类应该负责自己的验证,但是我认为这样做会违反单一职责原则,而且实际代码可能会因业务代码而变得混乱。你对此有什么想法吗? - Sam ツ
简短回答:这取决于情况。如果您使用了领域驱动设计,您可以在setter上验证所有属性 - 如果您担心单一职责,那肯定是一种安全的方法。我认为通过使用验证器策略场景,您仍然是安全的。验证器负责验证。它只是恰好被验证的对象引用。 - Ryan Bennett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接