热点聚焦:从设计模式谈业务开发

点击链接阅读原文,获取更多技术内容: https://developer.aliyun.com/article/1263195?utm_content=g_1000375168


【资料图】

作者 | 幽霄

来源 | 阿里开发者公众号

一、背景

前台业务同学在业务承接过程中总是抱怨大部分业务无法通过设计模式来承接,写的代码是越来越没有追求,理由是我无法预测未来的业务的发展,且设计模式更多的是在框架或中间件中使用。然而设计模式是对能力抽象出的通用模式,从哲学的角度来看世间万物皆尘土,事物都是可以抽象出共同的本质的东西。所以,难道只有底层能力可以抽象,业务逻辑部分就不可以抽象了?必须可以才是啊。

在前台业务承接过程中除了能力可以抽象,还有可以抽象出业务流程,假设在有这样一些业务场景,品搜和图搜、直播间评论和点赞、公域直播会场和私域商详透直播等等,这些各领域内的业务流程“大同小异”,因此都可以抽象出通用的业务流程节点。

但是通常在一个主干流程需要承接的场景有很多,比如直播间互动这个主干流程包括了直播间评论、点赞、求讲解、看证书、进场等等场景,所以我们需要通过主要流程进行进行多场景承接。但是这样还不够,在面对多端型多场景的情况下需要处理返回不同的数据模型。

综上所述,我们如何通过一个主干业务流程承接多个业务场景并在数据上可适配到多端型多场景,实现在服务端高质量高效率的“包接口”,下面会详细介绍。

二、业务承接

如果你面临的问题是在同一个业务域上承接多种类似的业务场景,每天在适配各种端型或者各种场景而对外提供接口时,为了保证应用系统的可扩展性和高效承接业务,那么可以按照如下步骤进行设计。

2.1 业务流程抽象

首先需要进行业务建模,抽象出用户用例或者user story,当然具体的粒度可以自己把控,具体如下:

2.1.1 用户用例

在直播间互动领域内的用户用例如下:

从整个系统出发,挖掘出面向不同的用户提供的能力有哪些,在这些用例背后需要进行的流程和节点又是什么。通过这些流程和节点才能进行后续的系统时序和流程抽象,举例如下

在互动领域内的流程和节点如下:

风控检查 评论持久化 评论上屏 评论进沟通

2.2.2 系统时序

基于用户用例进行分析,这些用例都需要经过什么的流程节点进行处理,然后将这些流程按照系统时序进行呈现。

到此基于上述的用例和时序是不是可以抽象出具体互动流程了,显而易见。

2.2.3 业务流程抽象

有了系统用例和系统时序这一步就比较简单,从系统时序里很容易可以抽象出具体的流程和流程中的处理节点,具体如下:

对于直播间互动领域可以抽象出的业务流程:风控检查->互动内容持久化-》消息上屏-》互动进IM 对于直播间分发领域可以抽象出的业务流程:直播推荐-》直播间基础信息-》直播流信息-》直播间品信息

到此,大家可以按照上述步骤在大脑里对自己的业务域进行抽象出来了。

2.2.4 设计模式固化主流程

按照业务主流程可以通过模板模式将处理流程固定下来,如下所示:

@Override@LiveLog(logResult = true)public InteractionResult interactionSubmit(MobileInteractionRequest request, InteractionLiveRoom liveRoom) {    Boolean needSave = MapUtils.getBoolean(request.getExtInfo(), LiveInteractionConstant.NEED_SAVE);    // 默认保存    InteractionResult saveResult = null;    if (Objects.isNull(request.getExtInfo()) || Objects.isNull(needSave) || needSave) {        saveResult = save(request, liveRoom);        if(Objects.nonNull(saveResult) && !saveResult.isSuccess()) {            return saveResult;        }    }    // 默认进沟通    InteractionResult chatResult;    if (Objects.isNull(request.getSendToChat()) || Boolean.parseBoolean(request.getSendToChat())) {        chatResult = sendToChat(request);        if(Objects.nonNull(chatResult) && !chatResult.isSuccess()) {            return chatResult;        }    }    if(Objects.nonNull(saveResult) && saveResult.isSuccess()) {        return saveResult;    }    return null;}/** * 互动行为保存到数据库或者缓存中 * * @param request * @return */protected abstract InteractionResult save(MobileInteractionRequest request, InteractionLiveRoom liveRoom);/** * 进沟通 * * @param request * @return */protected abstract InteractionResult sendToChat(MobileInteractionRequest request);

2.2 业务流程扩展

因在上述模版模式中预留了两个扩展点,所以在子类中可以通过扩展点进行扩展,举例如下:

如果有更多的场景就需要扩展实现上述两个扩展点进行扩展即可,这样保证了业务的高效承接。这里会有两个问题:

在程序运行时如何根据具体的场景选择哪个子类进行逻辑处理 如何进行适配端和场景返回的数据模型

针对第一个问题,其实就是如何去if else的问题,这里也给出比较经典的方案:

枚举法 表驱动法 策略模式+工厂模式

其中枚举法和表驱动法比较简单易用,原理就是将映射关系封装在枚举类或本地缓存中,这里简单介绍下如何通过策略模式消除if else。

// 策略接口public interface Opt {    int apply(int a, int b);}// 策略实现类@Component(value = \"addOpt\")public class AddOpt implements Opt {    @Autowired    xxxAddResource resource; // 这里通过Spring框架注入了资源    @Override    public int apply(int a, int b) {       return resource.process(a, b);    }}// 策略实现类@Component(value = \"devideOpt\")public class devideOpt implements Opt {    @Autowired    xxxDivResource resource; // 这里通过Spring框架注入了资源    @Override    public int apply(int a, int b) {       return resource.process(a, b);    }}// 策略处理@Componentpublic class OptStrategyContext{    private MapstrategyMap = new ConcurrentHashMap<>();    @Autowired    public OptStrategyContext(MapstrategyMap) {        this.strategyMap.clear();        this.strategyMap.putAll(strategyMap);    }    public int apply(Sting opt, int a, int b) {        return strategyMap.get(opt).apply(a, b);    }}

总结伪代码:

// 抽象类固定业务流程 预留扩展点public abstract class AbstractXxxx {  doXxx(Object context) {      // 节点1        doNode1(context);         // 节点2        doNode2(context);         // 节点3        doNode3(context);         // 节点n        ...    }    // 扩展点1    protected abstract Result doNode1(Object context);    // 扩展点2    protected abstract Result doNode2(Object context);    // 扩展点3    protected abstract Result doNode3(Object context);}    // 策略处理public class OptStrategyContext{    private MapstrategyMap = new ConcurrentHashMap<>();    static {        // 上述模版模式的实现类      strategyMap.put(\"business1\", Xxxx1);        strategyMap.put(\"business2\", Xxxx2);        strategyMap.put(\"business3\", Xxxx3);    }    // 初始化    public OptStrategyContext(MapstrategyMap) {        this.strategyMap.clear();        this.strategyMap.putAll(strategyMap);    }    public int doXxxx(Object context) {        return strategyMap.get(business).doXxxx(context);    }}

2.3 多场景多端型适配

上面我们只是通过模版模式抽象出了主干业务流程,但是如何适配不同的端型和不同的场景,返回不同的数据模型呢,这里有两种答案,一种是模版模式、另一种是“棒棒糖”模式,下面逐一介绍。

2.3.1 模版模式适配

既然是模版模式,这里的主干流程又是什么呢?主要跟我们解决的问题有关系,按照2.1中的流程步骤,可以抽象出固定的流程为:请求入参处理-》业务逻辑处理-》结果返回处理。

剩余60%,完整内容请点击下方链接查看: https://developer.aliyun.com/article/1263195?utm_content=g_1000375168

关键词: