24个写出漂亮代码的小技巧

您所在的位置:网站首页 数码小技巧 24个写出漂亮代码的小技巧

24个写出漂亮代码的小技巧

2023-05-19 18:39| 来源: 网络整理| 查看: 265

这篇文章我会总结一些实用的有助于提高代码质量的建议,内容较多,建议收藏!

内容概览:

提取通用处理逻辑

注解、反射和动态代理是 Java 语言中的利器,使用得当的话,可以大大简化代码编写,并提高代码的可读性、可维护性和可扩展性。

我们可以利用 注解 + 反射 和 注解+动态代理 来提取类、类属性或者类方法通用处理逻辑,进而避免重复的代码。虽然可能会带来一些性能损耗,但与其带来的好处相比还是非常值得的。

通过 注解 + 反射 这种方式,可以在运行时动态地获取类的信息、属性和方法,并对它们进行通用处理。比如说在通过 Spring Boot 中通过注解验证接口输入的数据就是这个思想的运用,我们通过注解来标记需要验证的参数,然后通过反射获取属性的值,并进行相应的验证。

@Data @Builder @AllArgsConstructor @NoArgsConstructor public class PersonRequest { @NotNull(message = "classId 不能为空") private String classId; @Size(max = 33) @NotNull(message = "name 不能为空") private String name; @Pattern(regexp = "(^Man$|^Woman$|^UGM$)", message = "sex 值不在可选范围") @NotNull(message = "sex 不能为空") private String sex; @Region private String region; @PhoneNumber(message = "phoneNumber 格式不正确") @NotNull(message = "phoneNumber 不能为空") private String phoneNumber; }

相关阅读:一坨一坨的 if/else 参数校验,终于被 SpringBoot 参数校验组件整干净了! 。

通过 注解 + 动态代理 这种方式,可以在运行时生成代理对象,从而实现通用处理逻辑。比如说 Spring 框架中,AOP 模块正是利用了这种思想,通过在目标类或方法上添加注解,动态生成代理类,并在代理类中加入相应的通用处理逻辑,比如事务管理、日志记录、缓存处理等。同时,Spring 也提供了两种代理实现方式,即基于 JDK 动态代理和基于 CGLIB 动态代理(JDK 动态代理底层基于反射,CGLIB 动态代理底层基于字节码生成),用户可以根据具体需求选择不同的实现方式。

@LogRecord(content = "修改了订单的配送地址:从“#oldAddress”, 修改到“#request.address”", bizNo="#request.deliveryOrderNo") public void modifyAddress(updateDeliveryRequest request){ // 查询出原来的地址是什么 LogRecordContext.putVariable("oldAddress", DeliveryService.queryOldAddress(request.getDeliveryOrderNo())); // 更新派送信息 电话,收件人、地址 doUpdate(request); }

相关阅读:美团技术团队:如何优雅地记录操作日志? 。

避免炫技式单行代码

代码没必要一味追求“短”,是否易于阅读和维护也非常重要。像炫技式的单行代码就非常难以理解、排查和修改起来都比较麻烦且耗时。

反例:

if (response.getData() != null && CollectionUtils.isNotEmpty(response.getData().getShoppingCartDTOList())) { cartList = response.getData().getShoppingCartDTOList().stream().map(CartResponseBuilderV2::buildCartList).collect(Collectors.toList()); }

正例:

T data = response.getData(); if (data != null && CollectionUtils.isNotEmpty(data.getShoppingCartDTOList())) { cartList = StreamUtil.map(data.getShoppingCartDTOList(), CartResponseBuilderV2::buildCartList); }

相关阅读:一个较重的代码坏味:“炫技式”的单行代码 。

基于接口编程提高扩展性

基于接口而非实现编程是一种常用的编程范式,也是一种非常好的编程习惯,一定要牢记于心!

基于接口编程可以让代码更加灵活、更易扩展和维护,因为接口可以为不同的实现提供相同的方法签名(方法的名称、参数类型和顺序以及返回值类型)和契约(接口中定义的方法的行为和约束,即方法应该完成的功能和要求),这使得实现类可以相互替换,而不必改变代码的其它部分。另外,基于接口编程还可以帮助我们避免过度依赖具体实现类,降低代码的耦合性,提高代码的可测试性和可重用性。

就比如说在编写短信服务、邮箱服务、存储服务等常用第三方服务的代码时,我们可以先先定义一个接口,接口中抽象出具体的方法,然后实现类再去实现这个接口。

public interface SmsSender { SmsResult send(String phone, String content); SmsResult sendWithTemplate(String phone, String templateId, String[] params); } /* * 阿里云短信服务 */ public class AliyunSmsSender implements SmsSender { ... } /* * 腾讯云短信服务 */ public class TencentSmsSender implements SmsSender { ... }

拿短信服务这个例子来说,如果需要新增一个百度云短信服务,直接实现 SmsSender 即可。如果想要替换项目中使用的短信服务也比较简单,修改的代码非常少,甚至说可以直接通过修改配置无需改动代码就能轻松更改短信服务。

操作数据库、缓存、中间件的代码单独抽取一个类

尽量不要将操作数据库、缓存、中间件的代码和业务处理代码混合在一起,而是要单独抽取一个类或者封装一个接口,这样代码更清晰易懂,更容易维护,一些通用逻辑也方便统一维护。

数据库:

public interface UserRepository extends JpaRepository { ... }

缓存:

@Repository public class UserRedis { @Autowired private RedisTemplate redisTemplate; public User save(User user) { } }

消息队列:

// 取消订单消息生产者 public class CancelOrderProducer{ ... } // 取消订单消息消费者 public class CancelOrderConsumer{ ... } 不要把业务代码放在 Controller 中

这个是老生常谈了,最基本的规范。一定不要把业务代码应该放在 Controller 中,业务代码就是要交给 Service 处理。

业务代码放到 Service 的好处 :

避免 Controller 的代码过于臃肿,进而难以维护和扩展。 抽象业务处理逻辑,方便复用比如给用户增加积分的操作可能会有其他的 Service 用到。 避免一些小问题比如 Controller 层通过 @Value注入值会失败。 更好的进行单元测试。如果将业务代码放在 Controller 中,会增加测试难度和不确定性。

错误案例:

@RestController public class UserController { @Autowired private UserRepository userRepository; @GetMapping("/users/{id}") public Result getUser(@RequestParam(name = "userId", required = true) Long userId) { User user = repository.findById(id) .orElseThrow(() -> new UserNotFoundException(id)); UserVO userVO = new UserVO(); BeanUtils.copyProperties(user, userVO);//演示使用 // 可能还有其他业务操作 ... return Result.success(userVO); } ... } 静态函数放入工具类

静态函数/方法不属于某个特定的对象,而是属于这个类。调用静态函数无需创建对象,直接通过类名即可调用。

静态函数最适合放在工具类中定义,比如文件操作、格式转换、网络请求等。

/** * 文件工具类 */ public class FileUtil extends PathUtil { /** * 文件是否为空 * 目录:里面没有文件时为空 文件:文件大小为0时为空 * * @param file 文件 * @return 是否为空,当提供非目录时,返回false */ public static boolean isEmpty(File file) { // 文件为空或者文件不存在直接返回 true if (null == file || false == file.exists()) { return true; } if (file.isDirectory()) { // 文件是文件夹的情况 String[] subFiles = file.list(); return ArrayUtil.isEmpty(subFiles); } else if (file.isFile()) { // 文件不是文件夹的情况 return file.length()


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3