zoukankan      html  css  js  c++  java
  • 从丑陋到优雅,让代码越变越美续集之服务器端数据校验

    数据校验是两方面的,客户端校验虽然可以大大减少服务器回调次数提升用户体验.但是客户端校验并不是万能的,从原理上说,客户端返回的数据都是不可信任的,服务器端校验必不可少.(关于客户端校验的总结:从丑陋到优雅,让代码越变越美(客户端检测方法思考) )


    总的来说,服务器端代码也经历了相似的几个过程:

    以判断一个输入是否是可以转换成整数为例,开始大家都会续项强写:

    Code1
    string str = txtTest.Text;
    if (!string.IsNullOrEmpty(str))
    {
        
    int? intResult = 0;
        
    if (int.TryParse(str, out intResult))
        {
            
    if(intResult>0 && intResult<100)
            {
                
    //success
            }
            
    else
            {
                ShowMessage(
    "输入必须大于0小于100");
            }
        }
        
    else
        {
            ShowMessage(
    "不能格式化为Int类型");
        }
    }
    else
    {
        ShowMessage(
    "输入为空");
    }

    看着就够麻烦,然后大家都会总结经验,将检测写成一个一个的函数:

    Code2
    protected bool IsInt(string str)
    {
        
    if (!string.IsNullOrEmpty(str))
        {
            
    int? intResult = 0;
            
    if (int.TryParse(str, out intResult))
            {
                
    return true;
            }
        }

        
    return false;
    }

    protected bool IsInRange(int max,int min,int input)
    {
        
    if (input > min && input < max)
            
    return true;
        
    else
            
    return false;
    }

    然后轻松调用:

    Code3
    if (IsInt(str))
    {
        
    if(IsInRange(100,0,int.Parse(str))
        {
            
    //success
        }
        
    else
        {
            ShowMessage(
    "输入必须大于0小于100");
        }
    }
    else
    {
        ShowMessage(
    "不能格式化为Int类型");
    }

    这样界面果然清爽多了..但是这样就满足了吗? 当然不是,这样的写法还是有很多缺点的,例如一大堆各种类型的判断函数很难记得住,加的方法多了还很容易重复,还有例如随着判断条件的增多那一堆"If"就让人火大~不优雅啊!!在这个追求优雅的时代,怎么能让这样的代码出在我们追求完美的人的手中? 一定要干掉它们!

    下面,我们就介绍一种经过改良的客户端检测解决方案:

    Code4
    vInfo info = vHelper.StartVerify(txtTest.Text)
        .IsNotNullOrEmpty(
    "输入为空")
        .IsInt(
    "不能格式化为Int类型")
        .Min(
    0"输入小于0")
        .Max(
    100"输入大于100")
        .EndVerify();

    ShowMessage(info);

    上边这个是检测字符串是否只能转换成int并在0到100范围的.下边这个是检测int类型是否属于0到100范围的.

    Code5
    vInfo info = vHelper.StartVerify(10)
        .IsNotNullOrEmpty(
    "输入为空")
        .Min(
    0"输入小于0")
        .Max(
    100"输入大于100")
        .EndVerify();

    ShowMessage(info);

    相似吧? 无论在检测的数据是任何类型,都只是同一种写法,浅显易记又优雅(囧!),返回的vInfo是一个贫血的实体类:

    Code6
    public class vInfo
    {
        
    private bool _Status;

        
    public bool Status
        {
            
    get { return _Status; }
            
    set { _Status = value; }
        }

        
    private string _Message;

        
    public string Message
        {
            
    get { return _Message; }
            
    set { _Message = value; }
        }
    }


    返回info是因为我们在后台代码中,往往需要根据检测结果做其他业务方面的处理,如果你不需要返回信息,并不想单独在外边写ShowMessage函数,可以在vInfo里面增加一个ShowMessage函数,让贫血的实体类不在贫血,实现像下面这样看起来更优雅的检测:

    Code7
    vInfo info = vHelper.StartVerify(10)
        .IsNotNullOrEmpty(
    "输入为空")
        .Min(
    0"输入小于0")
        .Max(
    100"输入大于100")
        .EndVerify()
        .ShowMessage();

    当然,不写在实体类,写在我们的检测基类中也可以.不过,ShowMessage的方式往往涉及具体业务逻辑,个人认为还是放到外层比较合适.

    废话不说了.先看看我们是如何实现这个检测的,我们先定义个检测基类:

    Code8
    public class v
    {
        
    protected bool Status;
        
    protected string Message;

        
    public vInfo EndVerify()
        {
            vInfo info 
    = new vInfo();
            info.Status 
    = Status;
            info.Message 
    = Message;
            
    return info;
        }
    }

    基类只有一个EndVerify(),这个函数用来返回具体检测结果信息.然后,我们根据各种检测类型构建不同的检测子类.校验不是一个类在战斗,这一刻,校验被工厂模式灵魂附体.....成功了,校验成功了,成功不是靠一个类实现的,他不是一个类....(sorry,扯远了..^_^)

    String类型检测子类:

    Code9
    public class vString:v
    {
        
    string stringT = null;

        
    public vString(string T)
        {
            stringT 
    = T;
            Status 
    = true;
            Message 
    = string.Empty;
        }

        
    public vString IsNotNullOrEmpty(string msg)
        {
            
    if (string.IsNullOrEmpty(stringT))
            {
                Status 
    = false;
                Message 
    = msg;
            }

            
    return this;
        }

        
    public vString IsInt(string msg)
        {
            
    if (!Status)
                
    return this;

            
    int intTemp = 0;
            Status 
    = int.TryParse(stringT, out intTemp);
            
    if (!Status)
                Message 
    = msg;

            
    return this;
        }

        
    public vString Min(int min, string msg)
        {
            
    if (!Status)
                
    return this;

            
    if (int.Parse(stringT) < min)
            {
                Status 
    = false;
                Message 
    = msg;
            }

            
    return this;
        }

        
    public vString Max(int max, string msg)
        {
            
    if (!Status)
                
    return this;

            
    if (int.Parse(stringT) > max)
            {
                Status 
    = false;
                Message 
    = msg;
            }

            
    return this;
        }
    }

    int类型检测子类:

    Code10
    public class vInt:v
    {
        
    int? intT = null;

        
    public vInt(int? T)
        {
            intT 
    = T;
            Status 
    = true;
            Message 
    = string.Empty;
        }

        
    public vInt IsNotNullOrEmpty(string msg)
        {
            
    if (intT == null)
            {
                Status 
    = false;
                Message 
    = msg;
            }

            
    return this;
        }

        
    public vInt Min(int min,string msg)
        {
            
    if (!Status)
                
    return this;

            
    if (intT < min)
            {
                Status 
    = false;
                Message 
    = msg;
            }

            
    return this;
        }

        
    public vInt Max(int max,string msg)
        {
            
    if (!Status)
                
    return this;

            
    if (intT > max)
            {
                Status 
    = false;
                Message 
    = msg;
            }

            
    return this;
        }
    }

    当然..还有更多更多的类在战斗..不过出场机会就是每个类都有.世界是不公平的,总是一部分人先富起来,然后更大部分的人穷下去......Sorry,牢骚了.各位大侠看明白就可以了.废话的看过就算了吧,忘了吧.

    最后,万事俱备只欠东风了..粮草兵马都有了,就差一个大将军了,大将军可是调动各个部队的灵魂人物,没有他仗就打不胜利了..下边有请我们的的大将,三军调度员,总设计师,联络官,发言人....(旁白:靠,小样你有完没完啊!!)

    Code11
    public class vHelper
    {
        
    int? intT = null;
        
    string stringT = null;

        
    public static vInt StartVerify(int? T)
        {
            
    return new vInt(T);
        }

        
    public static vString StartVerify(string T)
        {
            
    return new vString(T);
        }
    }

    vHelper类就是工厂类,它重载了StartVerify()函数,并根据参数的类型调度不同的检测类来完成检测过程.

    怎么样?很简单吧,只要扩展得好,检测不再是难事了吧? 把它们封装到一个dll中吧,这样,你就可以随时随地地校验了.

    (当然,没有最好只有更好,小弟在坐井观天呢,您有更好的方法吗?欢迎您指教!另外,对于链式编程,VS2005的智能提示好像有Bug.总不显示提示,不知道VS2008有没有修复.)

    最后附上完整代码: 点击下载

  • 相关阅读:
    Linux中的中断处理
    Yocto使用小技巧
    udev学习笔记汇总
    USB gadget学习笔记
    Linux常用命令
    Linux下软件安装方法
    278. First Bad Version
    MySQL的索引
    7. Reverse Integer
    排序算法
  • 原文地址:https://www.cnblogs.com/KenBlove/p/1426039.html
Copyright © 2011-2022 走看看