谈下新手程序员怎样写好复杂业务代码

2023-10-17 00:40

本文主要是介绍谈下新手程序员怎样写好复杂业务代码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

自己作为一名工作不足一年的程序员,来谈怎样写好复杂业务代码这个话题是很惶恐的。不过有些心得还是很想和大家交流。

自己工作以来,一直在看设计模式和代码整洁的书,平常工作内容主要是写业务代码,最大的感受就是完成需求容易,但把业务代码写简单、整洁易懂真的很不容易。随着慢慢地实践设计模式,参考别人的优秀代码,慢慢写多了,自己也有了这方面的体会或者说方法套路,和大家分享下。

一、懂得过程分解

写业务代码经常会碰到很比较复杂的业务流程,比如一个toB场景订单创建流程,就涉及很多处理过程,比如商品状态校验,买家购买资质校验,卖家售卖资质校验,销售规则校验,地址查询,发票查询,库存查询,库存校验,运费计算,促销(优惠卷、购物卡等)计算,价格计算,创建订单,促销占用,库存占用等等。这么多过程的确让人头大,一个Service方法一把梭写下来?老实说在复杂程度高的业务流程,一堆方法和类堆砌起来是最糟糕的写法了。谁都不愿意看到几百行或上千行的一个方法,复杂的业务逻辑穿插其中。

这时候必要的分解就很有必要了,简单来说就是分而治之,分治的时候把相同阶段的流程合并,就形成一个带有结构化的分治,分解如下:
在这里插入图片描述
到这里其实可以怎样实现思路比较清晰了,我们可以利用组合方式,创建订单的类,注入三个服务对象,分别为了初始化上下文,查询校验,执行。然后分别再分治实现每个阶段各个步骤,这样就很清晰了。(这里具体代码就不给出了)

二、利用领域驱动设计增强业务表达能力

上面的过程分解,很好地把复杂的业务流程进行合理的拆分成小的过程,使实现起来容易,并且代码也很清晰,但这个过程是比较发散的,而且每个过程只关心自己这个过程的处理,这样会有一个问题就是一些应该被复用的代码可能没有很好复用起来。这时候可以适当使用充血模型(可以理解为具有业务方法的模型),领域方法,将相关的领域能力聚合起来,达到复用的时候,也增强了业务表达能力。

1.1充血模型

比如价格的模型,价格类一般包含很多价格字段:商品金额总优惠,商品原价总价,商品改价金额,运费总价,运费改价金额,运费金额总优惠,税费总价,税费改价金额,税费金额总优惠,实付金额。假如我订单预览过程要算实付金额,很多人的做法是,在计算金额的节点把相应的运费、商品价格、税费捞出来,然后算一把实付金额,看起来没有啥问题,这样子做实际上业务表达能力是比较弱的,假如我别的地方也要算这个实付金额呢?重新算一遍,或者利用service封装的方法都不太好,最好的方式是把这个计算方法放进了价格这个模型,这样整个业务的表达能力瞬间就强了很多,实付价格本应属于这个价格模型的,就让它帮我们算就好,不必要在别的地方封装一个方法出来。

1.2 领域层方法

其实我们是可以按照领域驱动设计的思想,从系统中分别出各个领域,比如电商系统中,存在商品领域、促销领域、营销领域、会员领域、买家领域、库存领域等等,因此在过程分解中,把零散的相同领域内的方法聚合到一个领域类内,把领域知识聚合起来,知识能沉淀起来。

三、熟悉使用设计模式

能熟练应用设计模式到合适的场景,真的能事半功倍,我觉得新手程序员可以不妨深入学习下常用的设计模式,刻意用起来,然后慢慢体会设计模式的好处。比如策略模式、命令模式、工厂模式、责任链模式等等。

这里我结合一个开发例子说下策略模式,有一个多阶段支付的场景,就是一个订单要分多个阶段支付,比如预付款、货前款、到货款、结算款、质保款等等,支付后成功回调,就可能存在这几种阶段情况。不同阶段支付成功要进行不同的逻辑处理,按常规的处理,要安排上几个if-else了。这样的代码是不太好的,不好扩展,不好修改。如果应用策略设计模式会怎样呢?

1.1应用策略模式

上面说的几种支付阶段,就是对应几种策略。下面是具体实现细节

  1. 处理支付回调类:
@Slf4j
@MQConsumer(consumeMode = ConsumeMode.CONCURRENTLY,consumerGroup = MqConstants.ConsumerGroup.Payment.NOTIFY_PAYMENT_PAID_GROUP)
@RequiredArgsConstructor
public class PaymentPaidEventListener {@Autowiredprivate PaySuccessHandlerContext paySuccessHandlerContext;@MQSubscribe(topic = "${mq.topic.pay}",tag = MqConstants.ConsumerGroup.Payment.NOTIFY_PAYMENT_PAID_TAG)public void paySuccessConsumer(PayCenterPaySuccessPayload payload) {if (Objects.isNull(payload)) {log.warn("could not handle empty payCenterPaySuccessPayload.");return;}if (Objects.isNull(payload.getCurrentStage())) {log.warn("could not handle payCenterPaySuccessPayload without currentStage.param:{}", payload);return;}paySuccessHandlerContext.handle(payload);}
}
  1. 处理上下文:
@Service
@Slf4j
public class PaySuccessHandlerContext {@Autowiredprivate List<PaySuccessHandler> handlerList;public void handle(PayCenterPaySuccessPayload payload) {PaySuccessHandler handler = Optional.ofNullable(handlerList).orElse(null).stream().filter(h -> h.accept(String.valueOf(payload.getCurrentStage()))).findFirst().orElse(null);if (handler == null) {throw new RuntimeException("can not find paySuccessHandler");}handler.handle(payload);}}
  1. 各个不同支付阶段处理器
  • 3.1结算款支付处理器(其他阶段处理器类似)
@Service
@Slf4j
public class PayForSettlementHandler implements PaySuccessHandler {@Overridepublic void handle(PayCenterPaySuccessPayload payload) {// 处理过程}@Overridepublic boolean accept(String type) {return PayStageEnum.PAY_FOR_SETTLEMENT.getOrder().toString().equals(type);}
}

经策略模式处理后,是不是觉得代码很整洁,并且扩展性很好?要增加多一个新的支付阶段处理逻辑很容易,直接增加一个Handler就好了,需求变动修改某个阶段的处理逻辑,就在相应的处理器修改就好了,并且不存在误修改其他阶段处理逻辑的情况。

四、后记

在实际开发中,懂过程分解、领域驱动设计、设计模式真的比较容易在复杂的业务场景写出整洁、简单的代码,至少肯定不会写出很烂的代码。我个人认为在实际业务开发中,实现需求仅仅是底线而已,写出简单易懂、扩展性高的代码才是最有挑战性的。沉下心来,务实基础技术能力,不断锻炼分解问题的能力,抽象思维,写出一手好的代码来!与君共勉。

这篇关于谈下新手程序员怎样写好复杂业务代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/221801

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

JAVA调用Deepseek的api完成基本对话简单代码示例

《JAVA调用Deepseek的api完成基本对话简单代码示例》:本文主要介绍JAVA调用Deepseek的api完成基本对话的相关资料,文中详细讲解了如何获取DeepSeekAPI密钥、添加H... 获取API密钥首先,从DeepSeek平台获取API密钥,用于身份验证。添加HTTP客户端依赖使用Jav

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例

nginx-rtmp-module模块实现视频点播的示例代码

《nginx-rtmp-module模块实现视频点播的示例代码》本文主要介绍了nginx-rtmp-module模块实现视频点播,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录预置条件Nginx点播基本配置点播远程文件指定多个播放位置参考预置条件配置点播服务器 192.

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...