用于验证数据和创建对象的设计模式

Mar*_*ery 8 c# java design-patterns

我经常遇到这样的情况:我想通过传递一些给定的数据或者另一个对象来创建对象的实例,但数据或对象需要有效或处于正确的状态.我总是对"正确"的做法有点不清楚.这是我的例子:

鉴于此类:

class BusinessObject()
{
    const Threshold = 10;

    public BusinessObject(SetOfData<SomeType> setofdata)
    {
        // an example of some validation
        if (setofdata.count > Threshold)
        {
            // performance some business logic
            // set properties
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你这样做可能会遇到一些问题:

var setofdata = new SetOfData<SomeType>();

// if data is not valid then the object will be created incorrectly
var businessObject = new BusinessObject(setofdata);
Run Code Online (Sandbox Code Playgroud)

所以我的解决方案一直是:

class BusinessObjectBuilder()
{
    public BusinessObject Build(SetOfData<SomeType> setofdata)
    {
        // an example of some validation
        if (setofdata.count > Threshold)
            return new BusinessObject(setofdata);
        }
        else
        {
            return null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者将构造函数设为私有并添加静态工厂方法:

class BusinessObject()
{
    const Threshold = 10;

    public static Create(SetOfData<SomeType> setofdata)
    {
        if (setofdata.count > Threshold)
        {
            return new BusinessObject(setofdata);
        }
        else
        {
            return null;
        }
    }

    private BusinessObject(SetOfData<SomeType> setofdata)
    {
        // performance some business logic
        // set properties
    }
}
Run Code Online (Sandbox Code Playgroud)

理想情况下,如果数据无效,我不想抛出异常,因为在一个进程中可能会创建多个业务对象,并且如果一个验证失败并且捕获和抑制异常不好,我不希望整个进程失败.

此外,我读取的抽象工厂或工厂方法的所有示例都涉及传入某些类型或枚举以及正在构建和返回的正确对象.他们似乎永远不会涵盖这种情况.

那么这种情况下的约定是什么?任何建议将不胜感激.

Fen*_*ndy 11

对于许多情况,IMHO构造函数验证是最好的,除非设置了指定的参数,否则您需要确保不能创建任何对象.

public class BusinessObject
{
    const Threshold = 10;

    public BusinessObject(SetOfData<SomeType> setofdata)
    {
        // an example of some validation
        if (setofdata.count > Threshold)
        {
            throw new InvalidOperationException("Set data must be above treshold");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这在以下情况下执行不好:

  • 您可能有无效对象,例如处于草稿状态时等
  • 在需要默认构造函数时在ORM中使用
  • 如果发生严重的验证逻辑.

对于第1点和第2点,除了请求 - 验证 - 提交机制之外,我不能建议任何其他选项.

对于第3点,原因是,该类将为验证本身做太多,并创建一个单片代码.如果有很多验证逻辑,我建议用注入的验证器实现构建器模式,并制作BusinessObject内部构造函数.

public class BusinessObjectBuilder
{
    public BusinessObjectBuilder(IBusinessObjectValidator validator){
        this.validator = validator;
    }
    IBusinessObjectValidator validator;

    public BusinessObject Build(SetOfData<SomeType> setofdata)
    {
        // an example of some validation
        if (validator.IsValid(setofdata))
            return new BusinessObject(setofdata);
        }
        else
        {
            throw new //exception
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这强制执行模块化编程并防止单片代码.

这两个代码都是:

  • 容易测试
  • 容易审查
  • 扩展