• 图解设计模式:身份认证场景的应用


    文章首发在公众号(龙台的技术笔记),之后同步到博客园和个人网站:xiaomage.info

    今天和大家聊一聊,如何合理的将多种设计模式放到同一个业务场景中

    业务背景

    最近接到一个认证的需求,C 端用户在购买公司保险时,需要先进行 实名认证确认身份

    为了保证业务复用,单独将认证的逻辑拆分为微服务模块

    C 端用户下单购买保险的逻辑大致如下

    先说下关于认证相关的一些基本知识。简单来说,你如何证明你是你自己

    一些云服务厂商都会有关于验证身份的付费接口,接下来我们就以腾讯云姓名、身份证二要素认证为参考进行举例

    说完认证知识,我们再来拆解下用户购买保险的步骤

    1. 用户在前端发起认证行为
    2. 请求经过网关调用保险服务,保险服务调用认证服务
    3. 认证服务调用腾讯云认证付费 API,返回认证结果信息

    认证流程

    在整个块认证流程中,我们会讲解三种设计模式,按照顺序分别是策略、责任链、模板模式

    策略模式

    定义一组算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式使这些算法在客户端调用它们的时候能够互不影响地变化,客户端代指使用算法的代码

    我们拿认证来说,定义一个认证接口,然后实现二、三、四要素以及人脸识别实现;将这些实现类放到一个 Map 容器中,并和业务规定好对应的标识 Key,通过标识 Key 获取对应的认证策略实现

    如果真的像上面这么简单,if-else 判断加上拆解几个认证函数就可以搞得定,还真的不一定需要策略模式

    我们再延伸来看一种复杂场景:假设后续不满足于腾讯云的认证,为了保证可用性以及更多的流量,需要对接更多的认证平台

    可用性:平台的接口不太可能保证全年百分百可用,需要有容灾降级或者替换方案

    更多的流量:腾讯云认证接口限流 100次 / S

    这个时候策略模式的优点就体现出来了,简化代码的复杂性 以及 保证开闭原则,增加程序的健壮性以及可扩展性

    后续再增加三方认证平台和认证方式,都不需要改动原有逻辑,添加对应实现即可

    责任链模式

    在责任链模式中,多个处理器(参照拦截器)依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条,链条上的每个处理器 各自承担各自的处理职责

    这里主要将责任链模式应用于,规避无意义调用三方认证服务

    1. 已认证过的人员信息,在有效期内没必要再次调用
    2. 调用认证结果错误,依然会扣钱,比如说名称中包含非中文,身份证格式错误等等

    我们可以将处理器尽量职责单一,方便后续其它认证方式的 复用和编排

    模板方法

    模板方法模式在一个方法中定义一个 算法骨架,并将某些步骤推迟到 子类中实现。模板方法模式可以让子类在 不改变算法整体结构的情况下,重新定义算法中的某些步骤

    模版方法主要作用:复用性扩展性

    • 复用性:核心思想就是 父级定义公共实现由子级进行调取使用
    • 扩展性:在不修改方法逻辑的前提下,变更其中的某些步骤

    通俗来讲 : 定义一个抽象类 AbstractTemplate,并定义一个或若干抽象方法 abstractMethod。代码大致如下:

    public abstract class AbstractAuthenticationService<T extends AuthenticationRequest> {
    
        void before(T request) {
        }
    
        void after(T request) {
        }
    
      	// 抽象方法
        protected abstract void practicalExecute(T request);
    
        public void authentication(T request) {
          	// 前置拦截操作,包括不限于责任链模式调用
            before(request);
          	// 策略模式实现,调用具体认证类,比如二要素认证或三要素认证
            practicalExecute(request);
          	// 资源清理或记录认证完成信息
            after(request);
        }
    

    腾讯云二要素认证实现类,代码如下:

    @Slf4j
    @Component
    @RequiredArgsConstructor
    // BaseAuthenticationStrategy 是策略模式实现,定义了 mark、execute 方法
    public class NameIdCardAuthenticationByTencentResolver extends AbstractAuthenticationService<NameIdCardAuthenticationReqDTO>
            implements BaseAuthenticationStrategy<NameIdCardAuthenticationReqDTO> {
    
        private static final String SUCCESS = "0";
    
      	// 责任链容器
        private final NameIdCardHandlerChain nameIdCardHandlerChain;
    
        @Override
        public String mark() {
            return AuthenticationEnum.TENCENT.name();
        }
    
        @Override
        public void execute(NameIdCardAuthenticationReqDTO request) {
            authentication(request);
        }
    
        @Override
        public void before(NameIdCardAuthenticationReqDTO request) {
          	// 责任链调用
            nameIdCardHandlerChain.doFilter(request);
        }
    
        @Override
        public void practicalExecute(NameIdCardAuthenticationReqDTO request) {
            // 腾讯云二要素认证具体行为
        }
    
    }
    
    折叠

    最后总结

    抛出一个老生常谈的问题,学习设计模式有什么作用?

    设计模式主要是为了应对 代码的复杂性,让其满足 开闭原则,提高代码的 扩展性;合适的场景合理运用的设计模式,可以帮助代码实现 高内聚、低耦合 等的优点

    你无法决定别人的代码,但你可以决定自己的。时间充足的情况下,尽量以重构的方式去写每一行代码

    最后希望小伙伴读过文章后有所收获,祝好。

  • 相关阅读:
    Google Earth Engine(GEE)——显示和下载影像出现的问题
    js-读书笔记-函数式编程-applicative函数-join的实现
    没钱服务器安全怎么搞
    【LOJ#6718】九个太阳「弱」化版(循环卷积,任意模数NTT)
    ubuntu22.04下面安装josm
    php实现扫码二维码访问指定ID页面登录后自动跳转到该页面的方法
    AI 应用的全流程存储加速方案技术解析和实践分享
    GCC使用入门
    CSS Modules
    docker:CentOS安装 docker和默认安装目录
  • 原文地址:https://www.cnblogs.com/longtaiblog/p/16421929.html