安卓清理垃圾清理代码_从战中清理代码

安卓清理垃圾清理代码

从战中清除代码–验证

让我们直接从一个例子开始。 考虑一个简单的Web服务,该服务允许客户向商店下订单。 订单控制器的非常简化的版本可能如下所示–

@RestController
@RequestMapping(value = "/",consumes = MediaType.APPLICATION_JSON_VALUE,produces = MediaType.APPLICATION_JSON_VALUE)
public class OrderController {private final OrderService orderService;public OrderController(OrderService orderService) {this.orderService = orderService;}@PostMappingpublic void doSomething(@Valid @RequestBody OrderDTO order) {orderService.createOrder(order);}
}

和相应的DTO类

@Getter
@Setter
@ToString
public class OrderDTO {@NotNullprivate String customerId;@NotNull@Size(min = 1)private List<OrderItem> orderItems;@Getter@Setter@ToStringpublic static class OrderItem {private String menuId;private String description;private String price;private Integer quantity;}
}

从此DTO创建订单的最常见方法是将其传递给服务,根据需要对其进行验证,然后将其保存在数据库中

@Service
@Slf4j
class OrderService {private final MenuRepository menuRepository;OrderService(MenuRepository menuRepository) {this.menuRepository = menuRepository;}void createOrder(OrderDTO orderDTO) {orderDTO.getOrderItems().forEach(this::validate);log.info("Order {} saved", orderDTO);}private void validate(OrderItem orderItem) {String menuId = orderItem.getMenuId();if (menuId == null || menuId.trim().isEmpty()) {throw new IllegalArgumentException("A menu item must be specified.");}if (!menuRepository.menuExists(menuId.trim())) {throw new IllegalArgumentException("Given menu " + menuId + " does not exist.");}String description = orderItem.getDescription();if (description == null || description.trim().isEmpty()) {throw new IllegalArgumentException("Item description should be provided");}String price = orderItem.getPrice();if (price == null || price.trim().isEmpty()) {throw new IllegalArgumentException("Price cannot be empty.");}try {new BigDecimal(price);} catch (NumberFormatException ex) {throw new IllegalArgumentException("Given price is not in valid format", ex);}if (orderItem.getQuantity() == null) {throw new IllegalArgumentException("Quantity must be given");}if (orderItem.getQuantity() <= 0) {throw new IllegalArgumentException("Given quantity "+ orderItem.getQuantity()+ " is not valid.");}}
}

validate方法写得不好。 很难测试。 将来引入新的验证规则也很困难,因此删除/修改任何现有的验证规则也很困难。 从我的经验中,我看到大多数人通常在集成测试类中针对这种类型的验证检查编写一些通用断言,仅涉及一个或两个(或更多,但不是全部)验证规则。 因此,将来只能在“ 编辑”和“祈祷”模式下进行重构。

如果使用多态来替换这些条件,则可以改善代码结构。 我们创建一个通用的超级类型来表示一个验证规则

public interface OrderItemValidator {void validate(OrderItem orderItem);
}

下一步是创建验证规则实现,该实现将集中于DTO的单独验证区域。 让我们从菜单验证器开始

public class MenuValidator implements OrderItemValidator {private final MenuRepository menuRepository;public MenuValidator(MenuRepository menuRepository) {this.menuRepository = menuRepository;}@Overridepublic void validate(OrderItem orderItem) {String menuId = Optional.ofNullable(orderItem.getMenuId()).map(String::trim).filter(id -> !id.isEmpty()).orElseThrow(() -> new IllegalArgumentException("A menu item must be specified."));if (!menuRepository.menuExists(menuId)) {throw new IllegalArgumentException("Given menu [" + menuId + "] does not exist.");}}
}

然后商品说明验证器

public class ItemDescriptionValidator implements OrderItemValidator {@Overridepublic void validate(OrderItem orderItem) {Optional.ofNullable(orderItem).map(OrderItem::getDescription).map(String::trim).filter(description -> !description.isEmpty()).orElseThrow(() -> new IllegalArgumentException("Item description should be provided"));}
}

价格验证器

public class PriceValidator implements OrderItemValidator {@Overridepublic void validate(OrderItem orderItem) {String price = Optional.ofNullable(orderItem).map(OrderItem::getPrice).map(String::trim).filter(itemPrice -> !itemPrice.isEmpty()).orElseThrow(() -> new IllegalArgumentException("Price cannot be empty."));try {new BigDecimal(price);} catch (NumberFormatException ex) {throw new IllegalArgumentException("Given price [" + price + "] is not in valid format", ex);}}
}

最后,数量验证器

public class QuantityValidator implements OrderItemValidator {@Overridepublic void validate(OrderItem orderItem) {Integer quantity = Optional.ofNullable(orderItem).map(OrderItem::getQuantity).orElseThrow(() -> new IllegalArgumentException("Quantity must be given"));if (quantity <= 0) {throw new IllegalArgumentException("Given quantity " + quantity + " is not valid.");}}
}

这些验证器实现中的每一个现在都可以轻松地,彼此独立地进行测试。 关于它们每个的推理也变得更加容易。 将来的添加/修改/删除也是如此。

现在是接线部分。 我们如何将这些验证器与订单服务集成在一起?

一种方法是直接在OrderService构造函数中创建一个列表,并使用验证程序填充它。 或者我们可以使用Spring将List注入到OrderService中

@Service
@Slf4j
class OrderService {private final List<OrderItemValidator> validators;OrderService(List<OrderItemValidator> validators) {this.validators = validators;}void createOrder(OrderDTO orderDTO) {orderDTO.getOrderItems().forEach(this::validate);log.info("Order {} saved", orderDTO);}private void validate(OrderItem orderItem) {validators.forEach(validator -> validator.validate(orderItem));}
}

为了使它起作用,我们将必须将每个验证器实现声明为Spring Bean。

我们可以进一步改进抽象。 OrderService现在正在接受验证者列表。 但是,我们可以将其更改为仅了解OrderItemValidator类型,而无需其他任何操作。 这使我们可以灵活地将来注入单个验证器或任何组成的验证器。

因此,现在我们的目标是更改订单服务,以与单个验证器相同的方式来处理订单项验证器的组成。 有一个著名的设计模式称为
Composite让我们可以做到这一点。

让我们创建验证器接口的新实现,该接口将为复合

class OrderItemValidatorComposite implements OrderItemValidator {private final List<OrderItemValidator> validators;OrderItemValidatorComposite(List<OrderItemValidator> validators) {this.validators = validators;}@Overridepublic void validate(OrderItem orderItem) {validators.forEach(validators -> validators.validate(orderItem));}
}

然后,我们创建一个新的Spring配置类,该类将实例化并初始化此组合,然后将其公开为bean

@Configuration
class ValidatorConfiguration {@BeanOrderItemValidator orderItemValidator(MenuRepository menuRepository) {return new OrderItemValidatorComposite(Arrays.asList(new MenuValidator(menuRepository),new ItemDescriptionValidator(),new PriceValidator(),new QuantityValidator()));}
}

然后,我们通过以下方式更改OrderService类

@Service
@Slf4j
class OrderService {private final OrderItemValidator validator;OrderService(OrderItemValidator orderItemValidator) {this.validator = orderItemValidator;}void createOrder(OrderDTO orderDTO) {orderDTO.getOrderItems().forEach(validator::validate);log.info("Order {} saved", orderDTO);}
}

我们完成了!

这种方法的好处很多。 整个验证逻辑已完全从订购服务中抽象出来。 测试更容易。 将来的维护更加容易。 客户只知道一种验证器类型,而没有其他信息。

但是,上述所有方法也都存在一些问题。 有时人们对此设计不满意。 他们可能觉得这太抽象了,或者对于将来的维护他们将不需要太多的灵活性或可测试性。 我建议根据团队文化采用这种方法。 毕竟,在软件开发中没有唯一正确的方法。

请注意,为了本文方便,我在这里也做了一些简化。 其中包括在验证失败时引发通用IllegalArgumentException。 您可能希望生产级应用程序中有一个更特定/自定义的异常,以在不同情况之间进行标识。 十进制分析也很天真地完成,您可能要修复特定的格式,然后使用DecimalFormat对其进行解析。

完整的代码已上传到Github 。

翻译自: https://www.javacodegeeks.com/2017/05/clean-code-trenches.html

安卓清理垃圾清理代码

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

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

相关文章

rust为什么显示不了国服_捋捋 Rust 中的 impl Trait 和 dyn Trait

缘起一切都要从年末换工作碰上特殊时期, 在家闲着无聊又读了几首诗, 突然想写一个可以浏览和背诵诗词的 TUI 程序说起. 我选择了 Cursive 这个 Rust TUI 库. 在实现时有这么一个函数, 它会根据参数的不同返回某个组件(如 Button, TextView 等). 在 Cursive 中, 每个组件都实现了…

Sublime Text for Mac的快捷键

文章目录选择文本移动光标编辑文本查找/替换窗口显示书签和标记其它选择文本 快捷键说明CommandD先选中文本&#xff0c;再按CommandD&#xff0c;会选中下一个相同的文本&#xff0c;再继续按D(Command不放)则会选中下一个相同的文本&#xff0c;可以同时编辑被选中的文本Con…

zip unzip_zip和unzip上的Java要点

zip unzip压缩是编写文件时可以在我们的代码中发出的主要动作之一。 因此&#xff0c;我发现在zip和unzip上必不可少的简单Java代码段&#xff0c;并且必须易于访问。 要点是纯Java语言&#xff0c;并以zip格式存储两个文件。 完成后&#xff0c;打开打开的拉链并评估其内容。…

mysql不支持子查询_MySQL不支持子查询优化一例

一创建表 create table tt1(id int primary key, c1 INT);create table tt2(id int primary key, c2 INT);insert into tt1 value一创建表create table tt1(id int primary key, c1 INT);create table tt2(id int primary key, c2 INT);insert into tt1 values(1,1),(2,2),(3,3…

nginx配合python_人生苦短我用python[0x02] nginx与python结合

原标题&#xff1a;人生苦短我用python[0x02] nginx与python结合**文章内容为原创&#xff0c;欢迎转载请注明出处**背景nginx是一款高性能的http服务器&#xff0c;python是一门无论做系统开发还是业务逻辑开发都是非常不错的动态语言&#xff0c;现在流行微服务&#xff0c;微…

Linux 文件颜色含义

目录文件&#xff1a;蓝色 一般文件&#xff1a;白色 符号链接&#xff1a;紫色 设备文件&#xff1a;黄色 可执行文件&#xff1a;绿色 链接文件&#xff1a;青色 图片文件&#xff1a;粉红色 压缩文件&#xff1a;红色 其它文件&#xff1a;灰色 链接文件&#xff1…

Mysql索引使用情况_介绍mysql索引失效的情况

mysql视频教程栏目索引失效的情况。索引对于MySQL而言&#xff0c;是非常重要的篇章。索引知识点也巨多&#xff0c;要想掌握透彻&#xff0c;需要逐个知识点一一击破&#xff0c;今天来先来聊聊哪些情况下会导致索引失效。图片总结版相关免费学习推荐&#xff1a;mysql视频教程…

java8根据某个id删选_Java 8可选

java8根据某个id删选在编程时&#xff0c;我们都面临着&#xff08;最&#xff09; 臭名昭著的NullPointerException 。 而且我相信我们所有人都同意&#xff0c;遇到NullPointerException也是一种痛苦。 为了使读者了解最新情况&#xff0c;著名的计算机科学家Tony Hoare引入了…

emacs python ide_Emacs Python IDE win7 x64

安装平台 win7 x64 &#xff0c;emacs 23.3.1snippet工具&#xff0c;可自定义一些模板&#xff1a;.emacs 配置如下(add-to-list load-path "~/.emacs.d/yasnippet")(require yasnippet) ;; not yasnippet-bundle(yas/global-mode 1)自动完成工具&#xff0c;其实只…

解决阿里云 ssh 远程连接短时间没操作就会断掉的问题

在本地主机&#xff08;例如&#xff1a;你自己的 MacBook&#xff09;中打开 sshd 的配置文件&#xff0c;命令语句如下&#xff1a; sudo vim /etc/ssh/sshd_config注意&#xff1a;使用用户 root 编辑配置文件&#xff0c;否则会报错。 找到下面这个两行&#xff08;/Clie…

oracle查看jdk文档_Oracle JDK 9 Early Access文档已更新

oracle查看jdk文档Raymond Gallardo于2017年4月4日发布的针对Oracle JDK 9的抢先 访问文档已更新&#xff0c;今天宣布对Oracle JDK9文档的抢先访问页面进行了更新。 Gallardo重点介绍了一些更新的部分&#xff0c;包括Oracle JDK 9的新增功能 &#xff0c; Oracle JDK 9迁移指…

python3 selenium_Python3+Selenium3自动化测试-(准备)

Python3Selenium3自动化测试-(准备)最近在学习selenium自动化测试相关的内容&#xff0c;所以将实际准备情况做一记录&#xff0c;# 系统&#xff1a;win10(64位)# 浏览器&#xff1a;Chrome(67.0)、Firefox(61.0)、IE# python版本&#xff1a;3.6.5# Selenium&#xff1a;3.13…

MacBook如何通过键盘快捷键输入特殊字符_特殊符号

符号快捷键说明–[ Option ][ - ]破折号[ Option ] [ / ]除号≠[ Option ][ ]不等号≤[ Option ][ < ]≥[ Option ][ > ][ Option ][ \ ]左指双角引号[ Option ][ ’ ]拉丁文小写字母AE…[ Option ][ ; ]水平省略号≈[ Option ][ X ]约等于Ω[ Option ][ Z ]希腊文大写…

java 类 null_深入理解java中的null“类型”

本文研究的主要是java中的null“类型”的相关实例&#xff0c;具体介绍如下。先给出一道简单的null相关的题目&#xff0c;引发我们对null的探讨,后面会根据官方语言手册对null“类型”进行解读。题目&#xff1a;下面程序能正确运行吗&#xff1f;解析&#xff1a;输出应该为 …

wcg总决赛_关于总决赛

wcg总决赛可以将变量声明为final。 最终变量只能分配一次。 如果分配了最终变量&#xff0c;则将导致编译时错误&#xff0c;除非在分配前立即将其明确取消分配。 分配任何最终变量后&#xff0c;将永远无法对其进行更改。 如果变量引用任何对象的任何实例&#xff0c;它将继续…

python dump函数用法_Python中json库的load和dump函数

相信很多朋友都对python里面的json库非常熟悉&#xff0c;json这个东西简明易懂&#xff0c;还能储存数据&#xff0c;实在是非常方便。我一开始使用json是从爬虫接触的&#xff0c;那个时候只知道json.loads和json.dumps&#xff0c;当时ide确实会自动填充load函数和dump函数&…

如何彻底禁用Chrome浏览器的缓存功能

禁止Chrome浏览器的缓存功能有几种方式&#xff1a; 使用Shift F5强制刷新缓存。实际使用中我们发现&#xff0c;这种方法对于部分网页的更改并不能做到释放缓存的作用&#xff0c;尤其是无法释放DNS缓存。 使用隐身模式Shift Control N. 这种方法只能在打开的页面上消除之…

java int integer内存_java中一个integer对象的内存占用是多少?可以通过java方法输出吗?...

今天翻记录看到了自己15年3月份提的问题&#xff0c;现在已经18年6月份了&#xff1b;去年线上项目出现内存瓶颈&#xff0c;原因是缓存的玩家角色数据过多&#xff0c;在长时间不停服的情况下&#xff0c;导致数据越来越膨胀&#xff0c;之前没有清除无用缓存的机制&#xff0…

Linux命令行中的特殊符号_特殊字符

常用的特殊符号 符号说明#1.表示注释&#xff1b;2.命令提示符~表示用户主目录。切换到用户主目录下&#xff1a;cd ~&#xff0c;切换到用户主目录下的bin目录&#xff1a;cd ~/bin~表示当前目录。切换到当前目录下wwwroot目录&#xff1a;cd ~/wwwroot~-表示上次的工作目录。…

微信小程序css 华文琥珀_琥珀项目:较小的,面向生产力的Java语言功能

微信小程序css 华文琥珀Brian Goetz最近的消息欢迎来到琥珀&#xff01; 介绍Project Amber &#xff08; OpenJDK的一部分&#xff0c; 最初于1月提出 &#xff09;。 Goetz通过介绍“欢迎使用Amber项目&#xff0c;这是我们面向特定生产力的Java语言JEP的孵化场”的介绍打开了…