Data Validation Design Patterns

前端 未结 5 1531
灰色年华
灰色年华 2020-12-13 16:14

If I have a collection of database tables (in an Access file, for example) and need to validate each table in this collection against a rule set that has both common rules a

5条回答
  •  一向
    一向 (楼主)
    2020-12-13 16:29

    I would try with a combination of the Factory and Visitor patterns:

    using System;
    using System.Collections.Generic;
    
    namespace Example2
    {
        interface IVisitor
        {
            void Visit(Table1 table1);
            void Visit(Table2 table2);
        }
    
        interface IVisitable
        {
            void Accept(IVisitor visitor);
        }
    
        interface ILog
        {
            void Verbose(string message);
            void Debug(string messsage);
            void Info(string message);
            void Error(string message);
            void Fatal(string message);
        }
    
        class Error
        {
            public string Message { get; set; }
        }
    
        class Table1 : IVisitable
        {
            public int Id { get; set; }
            public string Data { get; set; }
            private IList InnerElements { get; } = new List();
    
            public void Accept(IVisitor visitor)
            {
                visitor.Visit(this);
    
                foreach(var innerElement in InnerElements)
                    visitor.Visit(innerElement);
            }
        }
    
        class Table2 : IVisitable
        {
            public int Id { get; set; }
            public int Data { get; set; }
    
            public void Accept(IVisitor visitor)
            {
                visitor.Visit(this);
            }
        }
    
        class Validator : IVisitor
        {
            private readonly ILog log;
            private readonly IRuleSet table1Rules;
            private readonly IRuleSet table2Rules;
    
            public Validator(ILog log, IRuleSet table1Rules, IRuleSet table2Rules)
            {
                this.log = log;
                this.table1Rules = table1Rules;
                this.table2Rules = table2Rules;
            }
    
            public void Visit(Table1 table1)
            {
                IEnumerable errors = table1Rules.EnforceOn(table1);
    
                foreach (var error in errors)
                    log.Error(error.Message);
            }
    
            public void Visit(Table2 table2)
            {
                IEnumerable errors = table2Rules.EnforceOn(table2);
    
                foreach (var error in errors)
                    log.Error(error.Message);
            }
        }
    
        class RuleSets
        {
            private readonly IRuleSetFactory factory;
    
            public RuleSets(IRuleSetFactory factory)
            {
                this.factory = factory;
            }
    
            public IRuleSet RulesForTable1 =>
                factory.For()
                    .AddRule(o => string.IsNullOrEmpty(o.Data), "Data1 is null or empty")
                    .AddRule(o => o.Data.Length < 10, "Data1 is too short")
                    .AddRule(o => o.Data.Length > 26, "Data1 is too long");
    
            public IRuleSet RulesForTable2 =>
                factory.For()
                    .AddRule(o => o.Data < 0, "Data2 is negative")
                    .AddRule(o => o.Data > 10, "Data2 is too big");
        }
    
        interface IRuleSetFactory
        {
            IRuleSet For();
        }
    
        interface IRuleSet
        {
            IEnumerable EnforceOn(T obj);
            IRuleSet AddRule(Func rule, string description);
        }
    
        class Program
        {
            void Run()
            {
                var log = new ConsoleLogger();
                var factory = new SimpleRules();
                var rules = new RuleSets(factory);
                var validator = new Validator(log, rules.RulesForTable1, rules.RulesForTable2);
    
                var toValidate = new List();
                toValidate.Add(new Table1());
                toValidate.Add(new Table2());
    
                foreach (var validatable in toValidate)
                    validatable.Accept(validator);
            }
        }
    }
    

提交回复
热议问题