设计模式在电商分期系统中的应用

设计模式在电商分期系统中的应用1 引言虽然设计模式常常被各种技术网站和教材提及,但是许多举例并不贴近我们的实际情况。有些示例甚至过于复杂,只为了解决一些与我们实际场景无关的问

大家好,欢迎来到IT知识分享网。

设计模式在电商分期系统中的应用

1 引言

虽然设计模式常常被各种技术网站和教材提及,但是许多举例并不贴近我们的实际情况。有些示例甚至过于复杂,只为了解决一些与我们实际场景无关的问题,这让人感到脱离实际且将简单场景复杂化。本文希望能够通过一些信也国际化电商中真实的代码案例,来简单的谈谈设计模式如何影响了这些代码,同时也探讨这些代码为什么会恰好使用了这些设计模式。

2 N家电商,一种订单

突然有一天,大家被召集起来,有一个电商合作的大型需求需要紧急开发,大家议论纷纷,产品缓缓拿出需求文档:

我们需要和一家在线电商合作,用户可以在电商的收银台界面选择我们的分期产品,我们有一套订单体系,需要和电商平台的支付单一一对应,并且这个订单有多种状态,每一种状态我们都需要通知到第三方,最终支付完成,用户完成订单购买。

我们的研发同学二话不说,心想这还不简单,立马写起了代码:

class Transaction{ private Long id; private String trxNo; private String merchantOrderNo; private BigDecimal amount; } class TransactionService { private OuterCallService outerCallService; private LoanService loanService; public init() //初始化订单 Transaction trx = new Transaction(); //初始化各种数值 trx.set(); trx.set(); outerCallService.notify(params); } public audit(Long trxId){ updateStatus(trxId, StatusEnum.AUDIT); //发起借贷的审核请求 loanService.audit(req); outerCallService.notify(params); } public paySuccess(){ updateStatus(trxId, StatusEnum.PAY_SUCCESS); outerCallService.notify(params); } /**其他状态修改**/ } class OuterCallService(){ public notify(Long trxId, String status){ //直接调用第三方接口 } }

很快开发同学就开发出了一段代码,并且成功经过了测试同学的测试,快速完成了产品的紧急需求,并且上线了。但是当研发同学回头看看这段代码的时候心里充满了不安,不断地问自己,如果每一个状态的变化背后都需要不同的业务处理,而不再仅仅是notify了怎么办?如果又多接了一家电商怎么办?如果一些流程里面还需要加入一些特殊的逻辑,主流程代码就会被改动,测试回归范围怎么办?我的单元测试怎么办?需要被大规模改动吗?这些代码我好像一个原则都没遵守,全混在一起了呀。带着这些忐忑与不安,很快迎来了第二家电商。又是一天清晨,产品又开了一个需求评审会:

我们这一次的电商是一个线下场景,我们面对的是线下用户,订单流程和之前的差不多也是通知为主,但是我们有几个场景不需要通知。并且线下场景订单信息会有不同,需要额外增加店铺信息。审核成功后不再等用户确认,而是自动发起打款。有可能存在同一个商品被多个人同时消费的场景,我们需要对商品单独加锁,保证商品订单一对一。

开发同学心想完了,两家主流程不同,背后的第三方调用通知实现也不同,日后肯定会有更多的变化,于是开始更加详细的代码设计。为了能够分开处理多家电商的不同的流程场景,研发同学脑海中立马浮现出了一副策略模式的画面。

3 策略模式

代码设计中的策略模式是一种行为型设计模式,它允许在运行时选择算法的行为,将每个算法封装在独立的类中,并使它们可以互相替换。以下是策略模式的特点:

  1. 封装算法:策略模式通过将不同的算法封装在各自的类中,使得每个算法都可以独立于其他算法进行修改和维护,这样做可以保持代码的灵活性和可维护性。
  2. 动态选择算法:策略模式允许在运行时根据不同的需求选择合适的算法。通过定义一个公共的接口或基类,客户端可以使用不同的具体策略对象来执行特定的算法,这种灵活性使得系统能够根据需要动态的切换算法,而无需修改核心代码。
  3. 解耦算法和客户端:策略模式可以将算法的实现与调用算法的客户端代码解耦。客户端只需要关注选择合适的策略对象并将其传递给上下文环境,而无需了解具体算法的实现细节,这样可以降低算法的复杂性,并且使得代码更加清晰易懂。

总结:策略模式的特点包括封装算法、动态选择算法以及解耦算法和客户端。这些特点使得策略模式成为一种强大的工具,能够帮助我们设计灵活、可扩展的代码结构。

interface TransactionStrategy{ init(Object... params); audit(Object... params); paySuccess(Object... params); } //线下电商 class OnlineTransactionStrategy implements Strategy{ public init(Object... params){ lockProduct(params); checkProductNotBeSaled(params); } public audit(Object... params){ loanService.audit(req); } public paySuccess(Object... params){ unlockProduct(params); } } //线上电商 class OfflineTransactionStrategy implements Straegy{ public init(Object... params){ //空方法 } public audit(Object... params){ loanService.audit(req); } public paySuccess(Object... params){ //空方法 } } //并且需要创建策略模式的环境类,以供外部调用 class TransactionStrategyContext { public static Strategy getStrategy(String merchantNo) { switch (merchantNo) { case "onlien": return new OnlineStrategy(); case "offline": return new OfflineStrategy(); default: throw new IllegalArgumentException("rewardType error!"); } } } 

在完成了策略模式的编写后(Notify也以相同形式实现,具体略),当然上述的代码其实可以更加优雅,比如说能否实现自动注册(@PostConstruct),而不再是手动注册的形式等等,需要大家自行探索。研发同学又紧锣密鼓地开始了原始代码的改造。

class Transaction{ //略。。 } class TransactionService { private OuterCallService outerCallService; private LoanService loanService; private TransctionstrategyContext transctionstrategyContext; public init(Object... params) //初始化订单 Transaction trx = new Transaction(); //初始化各种数值 trx.set(); trx.set(); transactionStrategyContext.getStrategy(merchantNo).init(params); if(needNotify){ notifyStrategyContext.getStrategy(merchantNo).notify(params); } } public audit(Long trxId){ updateStatus(trxId, StatusEnum.AUDIT); transactionStrategyContext.getStrategy(merchantNo).audit(params); if(needNotify){ notifyStrategyContext.getStrategy(merchantNo).notify(params); } } public paySuccess(){ updateStatus(trxId, StatusEnum.PAY_SUCCESS); transactionStrategyContext.getStrategy(merchantNo).paySuccess(params); if(needNotify){ notifyStrategyContext.getStrategy(merchantNo).notify(params); } } /**其他状态修改**/ } class OuterCallService(){ public notify(Long trxId, String status){ //直接调用第三方接口 } }

修改完了这段代码,研发同学对着这个代码左看右看,心想自动发起打款该怎么做呀?

4 状态模式

状态模式是一种行为型设计模式,用于处理对象在不同状态下的行为变化。它的主要特点如下:

  1. 封装了对象的状态:状态模式将对象的不同状态封装成独立的类,每个类负责处理该状态下的行为。通过封装,可以使得状态之间的转换更加清晰和可控。
  2. 通过多态实现状态切换:状态模式利用多态性来实现状态切换,即对象在不同状态下具有不同的行为。通过调用不同状态对应的方法,对象可以根据当前状态自动切换到合适的行为。
  3. 遵循开闭原则:状态模式能够很好地支持新的状态添加,而不需要修改已有的代码。当需要新增状态时,只需增加新的状态类,并在上下文中进行相应的关联,而无需修改原有的状态类或上下文类。

5 单例模式

单例模式是一种常见的设计模式,它确保一个类只有一个实例,并提供全局访问点。以下是单例模式的三个主要特点:

  1. 独一无二:单例模式确保一个类只有一个实例存在于内存中。这意味着无论何时使用该类,都只会获得同一个实例。这对于需要共享资源、限制对象创建数量或确保系统中某个状态的唯一性非常有用。
  2. 全局访问:由于单例模式只允许存在一个实例,因此可以方便地通过全局访问点来获取该实例。这样可以避免频繁地传递对象实例,简化代码结构,并使多个组件之间更容易通信。
  3. 延迟初始化:单例模式通常采用延迟初始化的方式创建实例,即在第一次请求获取实例时才进行实例化操作。这样能够避免不必要的资源消耗和性能损失,尤其在大型应用程序中更为重要。总之,单例模式通过独一无二、全局访问和延迟初始化等特点来提供一个全局唯一的实例,简化代码结构,提高系统性能,以及确保特定资源或状态的唯一性。
class Transaction{ //略。。 } //状态类的环境类 //单例 class StatusChangeSingleContext{ //创建 StatusChangeSingleContext 的一个对象 private static StatusChangeSingleContext instance = new StatusChangeSingleContext(); //让构造函数为 private,这样该类就不会被实例化 private StatusChangeSingleContext(){} //获取唯一可用的对象 public static StatusChangeSingleContext getInstance(){ return instance; } Map map = new HashMap<>(); public void put(String, StatusChange){ map.put(String, StatusChange); } public void invoke(String status, params){ map.get(status).changeStatus(params); } } //统一管理的状态抽象方法,外部只需要调用changeStatus() abstract class StatusChange{ private StatusChangeLogService statusChangeLogService; doAction(); register(); void changeStatus(String status, Tranaction trx, Object... params){ doAction(); changeStatus(params); statusChangeLogService.insertStatusChangeLog(params); notifyStrategyContext.notify(params); } } class InitStatusChange extends StatusChange{ private TransactionStrategyContext transctionstrategyContext; private InitStatusChange(){} public void register(){ StatusChangeSingleContext.getInstance().put("INIT", new InitStatusChange()) } public void doAction{ transactionStrategyContext.getStrategy(merchantNo).init } } class AuditStatusChange extends StatusChange{ private TransactionStrategyContext transctionstrategyContext; private AuditStatusChange(){} public void register(){ StatusChangeSingleContext.getInstance().put("AUDIT", new InitStatusChange()) } public void doAction{ transactionStrategyContext.getStrategy(merchantNo).init } } class PaySuccessStatusChange extends StatusChange{ private TransactionStrategyContext transctionstrategyContext; private PaySuccessStatusChange(){} public void register(){ StatusChangeSingleContext.getInstance().put("PAY_SUCCESS", new InitStatusChange()) } public void doAction{ transactionStrategyContext.getStrategy(merchantNo).init } } class TransactionService { private StatusChange statusChange; public init(Object... params) //初始化订单 Transaction trx = new Transaction(); //初始化各种数值 trx.set(); trx.set(); StatusChangeSingleContext.getInstance().invoke("INIT",params); } public audit(Long trxId){ StatusChangeSingleContext.getInstance().invoke("AUDIT", params); } public paySuccess(){ StatusChangeSingleContext.getInstance().invoke("PAY_SUCCESS",params); } /**其他状态修改**/ }

至此,研发露出了满意的笑,对于多个电商,不同流程,都有了良好的适配。

6 写在最后

尽管在实际的应用当中,仅仅订单管理所使用到的远不止这些设计模式,但是万变不离其宗,终究是不断地抽象,继承,多态。本文只是列举了三种常见的设计模式,所以在这里只是抛砖引玉。最后,无论是SOLID,还是各种设计原则,都并不是为了框定我们的设计而生的,他们只不过是一些前人走过的地方,恰巧走的人多了,就变成了路。设计模式也没有定式,如今衍生出来的设计模式也远不止23种,所有的这些理论、套路最后都只是服务于“好读,好改,好测”这三个终极目标。希望大家能够灵活应用,但是也不要走进靠设计模式“炫技”的怪圈。

作者介绍

xuzj ,现任信也科技国际化部门后端研发专家

来源:微信公众号:拍码场

出处:https://mp.weixin..com/s/RlYKT-eBiumFv95jqUi0cA

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/73858.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信