国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

實現一個對象驗證庫系列--1)接口介紹以及總體思路概述(請大神批評)

2019-11-14 13:53:42
字體:
來源:轉載
供稿:網友

前情回顧:

上一篇 0) 目錄以及庫結構介紹 簡單描述了下庫的代碼結構

本文將從接口部分闡述總體的思路

1) 接口介紹以及總體思路概述

如下圖,我總共定義了10個Interface

這些實際可分為兩類:

  • 為了支持 Fluent 語法格式而定義的各個創建者接口
    • IFluentRuleBuilder
    • IRuleBuilder
    • IRuleMessageBuilder
    • IValidateRuleBuilder
    • IValidatorBuilder
    • IValidatorSetter
  • 驗證操作涉及的規則、結果、驗證調用接口的定義:
    • IRuleSelector
    • IValidateResult
    • IValidateRule
    • IValidator

 

接下來我們首先闡述下驗證使用方式的接口設計思路,

然后再介紹 Fluent 格式的規則設置方式的設計思路。

(1)驗證使用方式的接口設計思路

我們首先考慮的用戶的驗證使用方式,而且我們是提供用戶自行設置驗證規則,不是只是提供一些固定的驗證規則,

那么用戶其實只是想給一個數據,然后拿到對應的結果就行

所以大致接口設想就是

public interface IValidator{	object Validate(object data);}

方法是這樣,用戶拿到返回值怎么方便使用呢?

思考一番,思路都是類似如下的

public interface IValidateResult{	bool IsValid { get; }  // 使用者肯定首先在乎驗證時候通過	List<ValidateFailure> Failures { get; }  // 如果不通過,會有什么錯誤信息}// 錯誤信息的類,使用者一般都是關注那個地方出錯,出了什么錯,原始的值是什么才導致了錯誤public class ValidateFailure{	public string Name { get; set; }	public object Value { get; set; }	public string Error { get; set; }}
// 所以接口可以改成這樣public interface IValidator{ IValidateResult Validate(object data);}

思考一下參數,object肯定不是滿足的:

public class ValidateContext{	public IRuleSelector RuleSelector { get; set; }		// 很多時候,用戶可能只是使用其中一些驗證規則,比如驗證學生信息時,大學生和幼兒園同學肯定是不一樣的														// 所以用戶得有一個實現如何選擇驗證規則方式的規則選擇器	public IEnumerable<string> RuleSetList { get; set; }  // 大部分時候,規則選擇器都是一樣,但是規則選擇只需用戶設置一些標志,一個默認實現的規則選擇器基本夠用了	public ValidateOption Option { get; set; }  		// 有時候用戶可能需要全部錯誤,但是有時會先check null,不為null才做其他驗證	public object ValidateObject { get; set; }}public enum ValidateOption{	StopOnFirstFailure,	Continue}public interface IRuleSelector{	bool CanExecute(IValidateRule rule, ValidateContext context);}// 所以最終接口這樣就可以了public interface IValidator{	IValidateResult Validate(ValidateContext context);}

接口方法這樣可以了,但是驗證規則如何保存呢?思考如下:

public interface IValidateRule{	string RuleSet { get; set; } // 規則分組的標志,大多數情況就可以滿足用戶對一個對象不同情境的驗證分組	IValidateRule NextRule { get; set; }  // 一個規則與其他規則常有關聯性,比如先check 為null,然后再check 長度,都放在一個class中肯定不方便我們定義與使用	string ValueName { get; set; }	// 有check 數據的名字屬性,這樣用戶可以改變這個名字	string Error { get; set; } // 有展示錯誤的屬性,這樣用戶可以改變這個屬性值	Func<ValidateContext, bool> Condition { get; set; }  // 規則分組如果不滿足用戶,就只能提供這樣的func讓用戶自行篩選了	Func<ValidateContext, string, string, IValidateResult> ValidateFunc { get; set; } // 之所以有這個屬性,是為了便利地拓展check的logic,不必每個新的規則check方式都必須寫一個ValidateRule類	IValidateResult Validate(ValidateContext context);  // 提供規則調用的接口}

(2)Fluent 格式的規則設置方式的設計思路

上面我們以及思考到了如何保存驗證規則,那么我們如何用 Fluent 的方式設置規則呢?

首先我們拋開 Fluent 的理念,想一下我們如何創建規則呢?

是不是這樣呢?

new ValidateRule() {	RuleSet = "xx",	ValueName = "xx"	.....}

回憶一下 Fluent 的方式,鏈式的語法,而且在我們這里用來設置驗證規則,簡直就是創建者模式的鏈式使用而已

ValidateRule.SetRuleSet("xx").SetValueName("xx")

 所以如下我們有了規則的創建者

public interface IValidateRuleBuilder{  string RuleSet { get; set; }  string ValueName { get; set; }  string Error { get; set; }  Func<ValidateContext, bool> Condition { get; set; }  IValidateRuleBuilder NextRuleBuilder { get; set; }  Func<ValidateContext, string, string, IValidateResult> ValidateFunc { get; set; }  IValidateRule Build(); // 大致與IValidateRule差不多,只是多了這個Build 方法}public interface IValidatorBuilder<T>{  IFluentRuleBuilder<T, TPRoperty> RuleFor<TProperty>(Expression<Func<T, TProperty>> expression);  void RuleSet(string ruleSet, Action<IValidatorBuilder<T>> action);  IValidator Build();}

  

Fluent 設計時都是大致設想最終效果類似什么樣,才能建立對應的接口這些定義

我們回想一下我們的最終效果是什么樣呢?

ValidatorBuilder.RuleFor(i => i.Age)        .Must(i => i >= 0 && i <= 18)        .OverrideName("student age")        .OverrideError("not student")    .ThenRuleFor(i => i.Name)        .Must(i => !string.IsNullOrWhiteSpace(i))        .OverrideName("student name")        .OverrideError("no name");

解釋一下我們最終的效果:

ValidatorBuilder.RuleFor(i => i.Age)  //一個 ValidatorBuilder 才能創建父級驗證規則,并會設置對應驗證的屬性        .Must(i => i >= 0 && i <= 18)  // 每個規則必須設置如何驗證方法		        .OverrideName("student age")        .OverrideError("not student")  // 設置一些需要復寫的信息		    .ThenRuleFor(i => i.Name)         // 只有設置完了一個規則的驗證方法之后才能建立子級規則        .Must(i => !string.IsNullOrWhiteSpace(i))        .OverrideName("student name")        .OverrideError("no name");

總體來說我們將一個規則的設置分成了幾個階段,并且這些階段是不可逆的,有著嚴格順序的

  • 初始創建父級驗證規則,并會設置對應驗證的屬性
  • 設置如何驗證方法
  • 填寫一些描述信息或者建立子級規則

如此我們的接口便會是如下:

public interface IValidatorBuilder<T>{	IFluentRuleBuilder<T, TProperty> RuleFor<TProperty>(Expression<Func<T, TProperty>> expression);	void RuleSet(string ruleSet, Action<IValidatorBuilder<T>> action);	IValidator Build();}// 對應 初始創建父級驗證規則,并會設置對應驗證的屬性 這個階段public interface IFluentRuleBuilder<T, TProperty>{}// 對應 設置如何驗證方法 這個階段public interface IRuleMessageBuilder<T, TValue>{	IFluentRuleBuilder<T, TProperty> ThenRuleFor<TProperty>(Expression<Func<T, TProperty>> expression);}// 對應 填寫一些描述信息或者建立子級規則 這個階段public interface IRuleBuilder<T, TValue> : IValidateRuleBuilder, IRuleMessageBuilder<T, TValue>, IFluentRuleBuilder<T, TValue>{	Func<object, TValue> ValueGetter { get; }	Expression<Func<T, TValue>> ValueExpression { get; }	void SetValueGetter(Expression<Func<T, TValue>> expression);}// 總結三個階段的最終定義

以上全部就是接口的設計思路

后面將慢慢的描述如何實現

 

 

NEXT: 2) 驗證器實現


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 顺昌县| 互助| 榆林市| 和林格尔县| 百色市| 汕尾市| 徐汇区| 中宁县| 德安县| 赤水市| 西平县| 绿春县| 柞水县| 鹤壁市| 光泽县| 来安县| 汶川县| 靖边县| 七台河市| 本溪市| 尖扎县| 玉林市| 洪湖市| 屏东市| 清涧县| 大连市| 喀什市| 通化市| 佛山市| 双桥区| 高要市| 应城市| 德昌县| 三原县| 兴海县| 汤阴县| 临汾市| 福贡县| 武川县| 科尔| 曲阳县|