规范模式异步
Specification pattern async
我正在尝试将 Specification pattern 应用于我的验证逻辑。但是我在异步验证方面遇到了一些问题。
假设我有一个实体 AddRequest
(有 2 个字符串 属性 文件名和内容)需要验证。
我需要创建 3 个验证器:
验证文件名是否不包含无效字符
验证内容是否正确
异步验证数据库中是否存在具有 FileName 的文件。在这种情况下,我应该有类似 Task<bool> IsSatisfiedByAsync
但是我怎样才能同时实现 IsSatisfiedBy
和 IsSatisfiedByAsync
?我应该创建 2 个接口,例如 ISpecification
和 IAsyncSpecification
,还是可以在一个接口中创建?
我的版本ISpecification
(我只需要And)
public interface ISpecification
{
bool IsSatisfiedBy(object candidate);
ISpecification And(ISpecification other);
}
和规格
public class AndSpecification : CompositeSpecification
{
private ISpecification leftCondition;
private ISpecification rightCondition;
public AndSpecification(ISpecification left, ISpecification right)
{
leftCondition = left;
rightCondition = right;
}
public override bool IsSatisfiedBy(object o)
{
return leftCondition.IsSatisfiedBy(o) && rightCondition.IsSatisfiedBy(o);
}
}
要验证文件是否存在,我应该使用:
await _fileStorage.FileExistsAsync(addRequest.FileName);
如果我真的需要执行异步操作,我该如何编写 IsSatisfiedBy
进行检查?
例如,我的验证器 (1) 用于 FileName
public class FileNameSpecification : CompositeSpecification
{
private static readonly char[] _invalidEndingCharacters = { '.', '/' };
public override bool IsSatisfiedBy(object o)
{
var request = (AddRequest)o;
if (string.IsNullOrEmpty(request.FileName))
{
return false;
}
if (request.FileName.Length > 1024)
{
return false;
}
if (request.FileName.Contains('\') || _invalidEndingCharacters.Contains(request.FileName.Last()))
{
return false;
}
return true
}
}
我需要创建 FileExistsSpecification 并像这样使用:
var validations = new FileNameSpecification().And(new FileExistsSpecification());
if(validations.IsSatisfiedBy(addRequest))
{ ... }
但是如果我需要异步,我该如何创建 FileExistsSpecification
?
我不知道,为什么您需要同步驱动模式中的异步操作。
想象一下,如果第一个结果是 false
并且你有两个或更多的异步检查,那将是一种性能浪费。
如果你想知道如何让异步请求恢复同步,你可以尝试使用以下方法:
public class FileExistsSpecification : CompositeSpecification
{
public override bool IsSatisfiedBy(object o)
{
var addRequest = (AddRequest)o
Task<bool> fileExistsResult = _fileStorage.FileExistsAsync(addRequest.FileName);
fileExistsResult.Wait();
return fileExistsResult.Result;
}
}
您还应该使用 泛型 方法。
我认为您的主要目标是确保在执行 child 规范时尽快完成评估复合规范的代码,一个或多个可能需要一段时间,是吗?在模式实现之外调用代码以异步调用规范总是可能的;那时你真的不关心。
那么,鉴于此,给你的 ISpecification 一个额外的 属性 怎么样?
public interface ISpecification
{
bool IsAsynchronous { get; }
bool IsSatisfiedBy(object o);
}
然后,对于 non-composite 同步或 asynchronous-type 规范,hard-code IsAsynchronous 的 return 值。但在合数中,以 children 为基础,即:
public class AndSpecification : ISpecification
{
private ISpecification left;
private ISpecification right;
public AndSpecification(ISpecification _left, ISpecification _right)
{
if (_left == null || _right == null) throw new ArgumentNullException();
left = _left;
right = _right;
}
public bool IsAsynchronous { get { return left.IsAsynchronous || right.IsAsynchronous; }
public override bool IsSatisfiedBy(object o)
{
if (!this.IsAsynchronous)
return leftCondition.IsSatisfiedBy(o) && rightCondition.IsSatisfiedBy(o);
Parallel.Invoke(
() => {
if (!left.IsSatisfiedBy(o)) return false;
},
() => {
if (!right.IsSatisfiedBy(o)) return false;
}
);
return true;
}
}
但更进一步,您不想浪费性能。因此,当有一个同步和一个异步时,为什么不首先评估快速同步 child?这是基本思想的 closer-to-finished 版本:
public class AndSpecification : ISpecification
{
private ISpecification left;
private ISpecification right;
public AndSpecification(ISpecification _left, ISpecification _right)
{
if (_left == null || _right == null) throw new ArgumentNullException();
left = _left;
right = _right;
}
public bool IsAsynchronous { get { return left.IsAsynchronous || right.IsAsynchronous; }
public override bool IsSatisfiedBy(object o)
{
if (!left.IsAsynchronous)
{
if (!right.IsAsynchronous)
{
return left.IsSatisfiedBy(o) && right.IsSatisfiedBy(o);
}
else
{
if (!left.IsSatisfiedBy(o)) return false;
return right.IsSatisfiedBy(o);
}
}
else if (!right.IsAsynchronous)
{
if (!right.IsSatisfiedBy(o)) return false;
return left.IsSatisfiedBy(o);
}
else
{
Parallel.Invoke(
() => {
if (!left.IsSatisfiedBy(o)) return false;
},
() => {
if (!right.IsSatisfiedBy(o)) return false;
}
);
return true;
}
}
}
But how can I implement both IsSatisfiedBy and IsSatisfiedByAsync? Should I create 2 interfaces like ISpecification and IAsyncSpecification or can I do that in one?
您可以同时定义同步和异步接口,但任何通用复合实现都必须只实现异步版本。
因为 asynchronous methods on interfaces mean "this might be asynchronous" 而同步方法意味着 "this must be synchronous",我会使用仅异步接口,例如:
public interface ISpecification
{
Task<bool> IsSatisfiedByAsync(object candidate);
}
如果你的许多规范是同步的,你可以帮忙做一个基础 class:
public abstract class SynchronousSpecificationBase : ISpecification
{
public virtual Task<bool> IsSatisfiedByAsync(object candidate)
{
return Task.FromResult(IsSatisfiedBy(candidate));
}
protected abstract bool IsSatisfiedBy(object candidate);
}
复合材料将是:
public class AndSpecification : ISpecification
{
...
public async Task<bool> IsSatisfiedByAsync(object o)
{
return await leftCondition.IsSatisfiedByAsync(o) && await rightCondition.IsSatisfiedByAsync(o);
}
}
public static class SpecificationExtensions
{
public static ISpecification And(ISpeicification @this, ISpecification other) =>
new AndSpecification(@this, other);
}
以及个别规格:
public class FileExistsSpecification : ISpecification
{
public async Task<bool> IsSatisfiedByAsync(object o)
{
return await _fileStorage.FileExistsAsync(addRequest.FileName);
}
}
public class FileNameSpecification : SynchronousSpecification
{
private static readonly char[] _invalidEndingCharacters = { '.', '/' };
public override bool IsSatisfiedBy(object o)
{
var request = (AddRequest)o;
if (string.IsNullOrEmpty(request.FileName))
return false;
if (request.FileName.Length > 1024)
return false;
if (request.FileName.Contains('\') || _invalidEndingCharacters.Contains(request.FileName.Last()))
return false;
return true;
}
}
用法:
var validations = new FileNameSpecification().And(new FileExistsSpecification());
if (await validations.IsSatisfiedByAsync(addRequest))
{ ... }
我正在尝试将 Specification pattern 应用于我的验证逻辑。但是我在异步验证方面遇到了一些问题。
假设我有一个实体 AddRequest
(有 2 个字符串 属性 文件名和内容)需要验证。
我需要创建 3 个验证器:
验证文件名是否不包含无效字符
验证内容是否正确
异步验证数据库中是否存在具有 FileName 的文件。在这种情况下,我应该有类似
Task<bool> IsSatisfiedByAsync
但是我怎样才能同时实现 IsSatisfiedBy
和 IsSatisfiedByAsync
?我应该创建 2 个接口,例如 ISpecification
和 IAsyncSpecification
,还是可以在一个接口中创建?
我的版本ISpecification
(我只需要And)
public interface ISpecification
{
bool IsSatisfiedBy(object candidate);
ISpecification And(ISpecification other);
}
和规格
public class AndSpecification : CompositeSpecification
{
private ISpecification leftCondition;
private ISpecification rightCondition;
public AndSpecification(ISpecification left, ISpecification right)
{
leftCondition = left;
rightCondition = right;
}
public override bool IsSatisfiedBy(object o)
{
return leftCondition.IsSatisfiedBy(o) && rightCondition.IsSatisfiedBy(o);
}
}
要验证文件是否存在,我应该使用:
await _fileStorage.FileExistsAsync(addRequest.FileName);
如果我真的需要执行异步操作,我该如何编写 IsSatisfiedBy
进行检查?
例如,我的验证器 (1) 用于 FileName
public class FileNameSpecification : CompositeSpecification
{
private static readonly char[] _invalidEndingCharacters = { '.', '/' };
public override bool IsSatisfiedBy(object o)
{
var request = (AddRequest)o;
if (string.IsNullOrEmpty(request.FileName))
{
return false;
}
if (request.FileName.Length > 1024)
{
return false;
}
if (request.FileName.Contains('\') || _invalidEndingCharacters.Contains(request.FileName.Last()))
{
return false;
}
return true
}
}
我需要创建 FileExistsSpecification 并像这样使用:
var validations = new FileNameSpecification().And(new FileExistsSpecification());
if(validations.IsSatisfiedBy(addRequest))
{ ... }
但是如果我需要异步,我该如何创建 FileExistsSpecification
?
我不知道,为什么您需要同步驱动模式中的异步操作。
想象一下,如果第一个结果是 false
并且你有两个或更多的异步检查,那将是一种性能浪费。
如果你想知道如何让异步请求恢复同步,你可以尝试使用以下方法:
public class FileExistsSpecification : CompositeSpecification
{
public override bool IsSatisfiedBy(object o)
{
var addRequest = (AddRequest)o
Task<bool> fileExistsResult = _fileStorage.FileExistsAsync(addRequest.FileName);
fileExistsResult.Wait();
return fileExistsResult.Result;
}
}
您还应该使用 泛型 方法。
我认为您的主要目标是确保在执行 child 规范时尽快完成评估复合规范的代码,一个或多个可能需要一段时间,是吗?在模式实现之外调用代码以异步调用规范总是可能的;那时你真的不关心。
那么,鉴于此,给你的 ISpecification 一个额外的 属性 怎么样?
public interface ISpecification
{
bool IsAsynchronous { get; }
bool IsSatisfiedBy(object o);
}
然后,对于 non-composite 同步或 asynchronous-type 规范,hard-code IsAsynchronous 的 return 值。但在合数中,以 children 为基础,即:
public class AndSpecification : ISpecification
{
private ISpecification left;
private ISpecification right;
public AndSpecification(ISpecification _left, ISpecification _right)
{
if (_left == null || _right == null) throw new ArgumentNullException();
left = _left;
right = _right;
}
public bool IsAsynchronous { get { return left.IsAsynchronous || right.IsAsynchronous; }
public override bool IsSatisfiedBy(object o)
{
if (!this.IsAsynchronous)
return leftCondition.IsSatisfiedBy(o) && rightCondition.IsSatisfiedBy(o);
Parallel.Invoke(
() => {
if (!left.IsSatisfiedBy(o)) return false;
},
() => {
if (!right.IsSatisfiedBy(o)) return false;
}
);
return true;
}
}
但更进一步,您不想浪费性能。因此,当有一个同步和一个异步时,为什么不首先评估快速同步 child?这是基本思想的 closer-to-finished 版本:
public class AndSpecification : ISpecification
{
private ISpecification left;
private ISpecification right;
public AndSpecification(ISpecification _left, ISpecification _right)
{
if (_left == null || _right == null) throw new ArgumentNullException();
left = _left;
right = _right;
}
public bool IsAsynchronous { get { return left.IsAsynchronous || right.IsAsynchronous; }
public override bool IsSatisfiedBy(object o)
{
if (!left.IsAsynchronous)
{
if (!right.IsAsynchronous)
{
return left.IsSatisfiedBy(o) && right.IsSatisfiedBy(o);
}
else
{
if (!left.IsSatisfiedBy(o)) return false;
return right.IsSatisfiedBy(o);
}
}
else if (!right.IsAsynchronous)
{
if (!right.IsSatisfiedBy(o)) return false;
return left.IsSatisfiedBy(o);
}
else
{
Parallel.Invoke(
() => {
if (!left.IsSatisfiedBy(o)) return false;
},
() => {
if (!right.IsSatisfiedBy(o)) return false;
}
);
return true;
}
}
}
But how can I implement both IsSatisfiedBy and IsSatisfiedByAsync? Should I create 2 interfaces like ISpecification and IAsyncSpecification or can I do that in one?
您可以同时定义同步和异步接口,但任何通用复合实现都必须只实现异步版本。
因为 asynchronous methods on interfaces mean "this might be asynchronous" 而同步方法意味着 "this must be synchronous",我会使用仅异步接口,例如:
public interface ISpecification
{
Task<bool> IsSatisfiedByAsync(object candidate);
}
如果你的许多规范是同步的,你可以帮忙做一个基础 class:
public abstract class SynchronousSpecificationBase : ISpecification
{
public virtual Task<bool> IsSatisfiedByAsync(object candidate)
{
return Task.FromResult(IsSatisfiedBy(candidate));
}
protected abstract bool IsSatisfiedBy(object candidate);
}
复合材料将是:
public class AndSpecification : ISpecification
{
...
public async Task<bool> IsSatisfiedByAsync(object o)
{
return await leftCondition.IsSatisfiedByAsync(o) && await rightCondition.IsSatisfiedByAsync(o);
}
}
public static class SpecificationExtensions
{
public static ISpecification And(ISpeicification @this, ISpecification other) =>
new AndSpecification(@this, other);
}
以及个别规格:
public class FileExistsSpecification : ISpecification
{
public async Task<bool> IsSatisfiedByAsync(object o)
{
return await _fileStorage.FileExistsAsync(addRequest.FileName);
}
}
public class FileNameSpecification : SynchronousSpecification
{
private static readonly char[] _invalidEndingCharacters = { '.', '/' };
public override bool IsSatisfiedBy(object o)
{
var request = (AddRequest)o;
if (string.IsNullOrEmpty(request.FileName))
return false;
if (request.FileName.Length > 1024)
return false;
if (request.FileName.Contains('\') || _invalidEndingCharacters.Contains(request.FileName.Last()))
return false;
return true;
}
}
用法:
var validations = new FileNameSpecification().And(new FileExistsSpecification());
if (await validations.IsSatisfiedByAsync(addRequest))
{ ... }