避免许多if块进行验证检查

在某些情况下,我们需要先验证输入数据,然后再将其发送到业务逻辑层进行处理,计算等。这种验证在大多数情况下是孤立完成的,或者可能包括与外部数据或其他输入的某些交叉检查。 看下面的示例,该示例验证用户输入的注册数据。

public void register(String email, String name, int age) {String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"+ "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";Pattern pattern = Pattern.compile(EMAIL_PATTERN);List<String> forbiddenDomains = Arrays.asList("domain1", "domain2");if ( email == null || email.trim().equals("")){throw new IllegalArgumentException("Email should not be empty!");}if ( !pattern.matcher(email).matches()) {throw new IllegalArgumentException("Email is not a valid email!");}if ( forbiddenDomains.contains(email)){throw new IllegalArgumentException("Email belongs to a forbidden email");}if ( name == null || name.trim().equals("")){throw new IllegalArgumentException("Name should not be empty!");}
if ( !name.matches("[a-zA-Z]+")){throw new IllegalArgumentException("Name should contain only characters");}
if ( age <= 18){throw new IllegalArgumentException("Age should be greater than 18");}
// More code to do the actual registration
}

这种方法的循环复杂性确实很高,如果要验证的字段更多或添加实际的业务逻辑,则可能会变得更糟。 当然,我们可以将代码分为两个私有方法(validate,doRegister),但是几个if块将被移到私有方法的问题。 除此以外,该方法还要做很多事情,而且很难测试。 当我要求初级开发人员重构该代码并使之更具可读性,可测试性和可维护性时,他们像个外星人一样看着我:“我应该如何简化它。 我该如何替换这些if块?” 好了,这里的解决方案效果很好,遵循“单一责任模式”,使代码更易于阅读。

为了更好地理解解决方案,请将每个if块都视为验证规则。 现在是时候为这些规则建模了。

首先用一种方法创建一个接口。 用Java 8术语,它称为功能接口 ,如下所示。

public interface RegistrationRule{void validate();
}

现在是时候将每个验证检查转换为注册规则了。 但是在我们这样做之前,我们需要解决一个小问题。 我们的界面实现应该能够处理注册数据,但是如您所见,我们拥有不同类型的数据。 因此,我们这里需要将注册数据封装在单个对象中,如下所示:

public class RegistrationData{private String name;private String email;private int age;
// Setters - Getters to follow
}

现在我们可以改善功能界面:

public interface RegistrationRule{
void validate(RegistrationData regData);
}

并开始编写我们的规则集。 例如,让我们尝试实现电子邮件验证。

public class EmailValidatationRule implements RegistrationRule{private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"+ "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";private final Pattern pattern = Pattern.compile(EMAIL_PATTERN);
@Overridepublic void validate(RegistrationData regData) {if ( !pattern.matcher(regData.email).matches()) {throw new IllegalArgumentException("Email is not a valid email!");}
}

显然,我们在上述类中隔离了电子邮件验证。 我们可以对初始实施的所有规则执行相同的操作。 现在,我们可以重新编写我们的注册方法以使用验证规则。

List<RegistrationRule> rules = new ArrayList<>();rules.add(new EmailValidatationRule());rules.add(new EmailEmptinessRule());rules.add(new ForbiddenEmailDomainsRule());rules.add(new NameEmptinessRule());rules.add(new AlphabeticNameRule());for ( RegistrationRule rule : rules){rule.validate(regData);}

为了变得更好,我们可以使用Factory模式和一个静态方法get()创建一个Rules类,该方法将返回规则列表。 我们的最终实现将如下所示

for ( RegistrationRule rule : Rules.get()){rule.validate(regData);
}

将我们的注册方法的初始版本与最终版本的注册方法进行比较会产生疑问。 我们的新版本更紧凑,更易读,当然也更具可测试性。 实际的检查已移至单独的类(也易于测试),并且所有方法仅做一件事(请始终牢记这一点)。

翻译自: https://www.javacodegeeks.com/2014/07/avoiding-many-if-blocks-for-validation-checking.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362478.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

谷歌逐步取消对IE6的支持

1月30日&#xff0c;据国外媒体报道&#xff0c;谷歌周五宣布&#xff0c;截至3月1日&#xff0c;谷歌将不再其谷歌Docs和谷歌网站服务支持IE6。如果IE用户想使用那些产品&#xff0c;他们必须至少升级到版本7&#xff0c;如同“其他许多公司已经停止支持如Internet Explorer 6…

国内手机号正则表达式

java的写法&#xff1a; String pattern "^((1[358][0-9])|(14[57])|(17[0678])|(19[7]))\\d{8}$"; javascript的写法&#xff1a; var pattern /^((1[358][0-9])|(14[57])|(17[0678])|(19[7]))\d{8}$/; 更多专业前端知识&#xff0c;请上 【猿2048】www.mk2048.co…

layui 子页面写弹出框覆盖父页面,以及给弹框中的表单赋值

咋说呢&#xff0c;因为对 layui 不太熟悉&#xff0c;这个弹出框搞了好久&#xff0c;看了好多解决方案&#xff0c;大致尝试了一下其中几种&#xff0c;在坑中无法自拔。。。总之终于搞出来了&#xff0c;在这里分享一下我的笔记。 着急的直接 戳这里 看解决代码。 尝试 1、…

html实现文字垂直居中且设置间隔

使用table和table-call布局 将表格作为一个table表&#xff0c;使用table-cell定义每个单元格的布局为table-cell, 抛出display的有效值 单元格中间的间隔使用 border-spacing:10px; border-collapse: separate;定义单元格vertical-align: middle; display: table-cell;代码源码…

入世与出世

同情恰好有两种。一种同情怯懦感伤&#xff0c;实际上只是心灵的焦灼。看到别人的不幸&#xff0c;急于尽快脱身出来&#xff0c;以免受到感动&#xff0c;陷入难堪的境地。这种同情根本不是对别人的痛苦抱有同感&#xff0c;而只是本能地予以抗拒&#xff0c;免得它触及自己的…

Hibernate隐藏的宝石:pooled-lo优化器

介绍 在这篇文章中&#xff0c;我们将揭示一个序列标识符生成器&#xff0c;​​它结合了标识符分配效率和与其他外部系统的互操作性&#xff08;同时访问底层数据库系统&#xff09;。 传统上&#xff0c;有两种序列标识符策略可供选择。 序列标识符&#xff0c;对于每个新值…

vue inheritAttrs、$attrs和$listeners使用

inheritAttrs、$attrs和$listeners使用场景&#xff1a; 组件传值&#xff0c;尤其是祖孙组件有跨度的传值。 &#xff08;1&#xff09;inheritAttrs 属性说明&#xff1a;https://cn.vuejs.org/v2/api/#inheritAttrs 说明比较晦涩。 组件传值一般是通过props传值的。inhe…

鼠标滚轮事件及解决滚轮事件多次触发问题

转载&#xff1a;https://www.cnblogs.com/jjxhp/p/11736066.html#_label0 一、滚轮事件的 js 写法 二、jQuery写法 三、参考 四、滚轮事件滚动过快&#xff0c;事件触发两次 一、js //判断鼠标滚轮滚动方向 if (window.addEventListener){ //FF,火狐浏览器会识别该方法wind…

Leetcode 2976. Minimum Cost to Convert String I

Leetcode 2976. Minimum Cost to Convert String I 1. 解题思路2. 代码实现 题目链接&#xff1a;2976. Minimum Cost to Convert String I 1. 解题思路 这道题思路上其实是非常直接的&#xff0c;本质上就是给出有向图之后&#xff0c;求出有向图上任意两点之间的最短距离&…

仍不切换到Java 8的6个理由

Java 8很棒。 期。 但是……在我们有机会玩耍并玩弄它之后&#xff0c;就该退出了&#xff0c;避免吃盐。 所有的好东西都是有代价的&#xff0c;在这篇文章中&#xff0c;我将分享Java 8的主要痛点。请确保在升级和放弃7之前您已经意识到了这些痛点。 1.并行流实际上会使您减…

硬币回收价格

1957年 1分 1元1960年 1分 80元 1962年 1分 30元1965年 1分 350元1966年 1分 180元1967年 1分 350元1968年 1分 88元1969年 1分 150元1977年 1分 320元1981年 1分 5元1988年 1分 300元1989年 1分 150元1990年 1分 180元1995年 1分 0.5元1955年 2分 15元1957年 2分 2元1958年 …

13 字符串相关函数

# ### 字符串相关函数 # *capitalize 字符串首字母大写 strvar "this is a dog" res strvar.capitalize() print(res)# *title 每个单词的首字母大写 (非字母隔开的单词) strvar "this is123a dog" res strvar.title() print(res)# *upper 将所有字母变…

Vue 生命周期LIFECYCLE是8个吗?

vue生命周期钩子个数是&#xff1a;11个。 export const LIFECYCLE_HOOKS [beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed,activated,deactivated,errorCaptured] github地址&#xff1a; https://github.com/vuejs/vue/blob/dev/…

鼠标滚轮切屏效果

某天发现一个网站《北京新鸿儒世纪网络技术有限公司》&#xff0c;一开始打开&#xff0c;哇&#xff0c;好简单啊&#xff0c;特别是首页&#xff0c;就一张图&#xff0c;后来发现里面有挺多小细节的&#xff0c;比如&#xff1a;做了媒体响应式、滚轮切屏&#xff08;第一次…

JavaFX技巧11:更新只读属性

自定义控件通常具有“只读”属性。 这意味着不能从控件外部进行设置&#xff0c;甚至不能从自己的皮肤类别进行设置。 通常&#xff0c;控件的行为会导致更改只读属性。 在JavaFX中&#xff0c;可以在控件本身和皮肤中实现此行为。 因此&#xff0c;有时我们最终希望通过皮肤来…

DVT和ADVT - 为数不多的DICOM测试工具说明AND下载

1、 前言做DICOM研究、开发和应用的人&#xff0c;最头疼的就是没有充分的工具和手段来进行测试&#xff0c;所以无法知道自己的程序、软件是否正确&#xff0c;能否正确地与其他设备进行DICOM连接&#xff1f;连接出错的原因在哪里&#xff1f;改正的话该从哪里下手&#xff1…

高阶函数 实现sum(2)(3) 柯里化

<!DOCTYPE html><html><head><meta charset"utf-8" /><title>高阶函数 实现sum(2)(3)</title></head><body><script type"text/javascript">function add() {var args [].slice.call(arguments);v…

设置和重置ssh key

查看本地是否有已经生成好的ssh key $ cat ~/.ssh/id_rsa.pub 若有,先删除: $ cd ~ $ rm -rf .ssh 重新生成ssh key ssh-keygen -t rsa -C "youemailexample.com" 提示输入密码或确认密码 直接全部回车即可 查看新生成的ssh key $ cat ~/.ssh/id_rsa.pub 然后获取到密…

小程序 自定义组件报错[“usingComponents“][“my-list“] 未找到

根据官网案例写了一个自定义组件&#xff0c;引入时总是报这个错误。 后面在社区里面找到了解决办法&#xff0c;把上面配置中改成&#xff1a;"my-list": "/components/my-list/my-list" 就可以了。 具体原因&#xff1a;官方文档上的自定义组件是 4 个文…

编写干净的测试–验证或不验证

在编写使用模拟对象的单元测试时&#xff0c;请遵循以下步骤&#xff1a; 配置我们的模拟对象的行为。 调用测试的方法。 验证是否已调用模拟对象的正确方法。 第三步的描述实际上有点误导&#xff0c;因为通常我们最终会验证是否调用了正确的方法以及未调用模拟对象的其他…