阿里妹导读
2.1 业务流程抽象
2.1.1 用户用例
从整个系统出发,挖掘出面向不同的用户提供的能力有哪些,在这些用例背后需要进行的流程和节点又是什么。通过这些流程和节点才能进行后续的系统时序和流程抽象,举例如下
在互动领域内的流程和节点如下:
- 风控检查
- 评论持久化
- 评论上屏
-
评论进沟通
2.2.2 系统时序
基于用户用例进行分析,这些用例都需要经过什么的流程节点进行处理,然后将这些流程按照系统时序进行呈现。
到此基于上述的用例和时序是不是可以抽象出具体互动流程了,显而易见。
2.2.3 业务流程抽象
有了系统用例和系统时序这一步就比较简单,从系统时序里很容易可以抽象出具体的流程和流程中的处理节点,具体如下:
-
对于直播间互动领域可以抽象出的业务流程:风控检查->互动内容持久化-》消息上屏-》互动进IM -
对于直播间分发领域可以抽象出的业务流程:直播推荐-》直播间基础信息-》直播流信息-》直播间品信息
到此,大家可以按照上述步骤在大脑里对自己的业务域进行抽象出来了。
2.2.4 设计模式固化主流程
按照业务主流程可以通过模板模式将处理流程固定下来,如下所示:
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。
// 策略接口
public interface Opt {
int apply(int a, int b);
}
// 策略实现类
"addOpt") (value =
public class AddOpt implements Opt {
xxxAddResource resource; // 这里通过Spring框架注入了资源
public int apply(int a, int b) {
return resource.process(a, b);
}
}
// 策略实现类
"devideOpt") (value =
public class devideOpt implements Opt {
xxxDivResource resource; // 这里通过Spring框架注入了资源
public int apply(int a, int b) {
return resource.process(a, b);
}
}
// 策略处理
public class OptStrategyContext{
private Map strategyMap = new ConcurrentHashMap<>();
public OptStrategyContext(Map strategyMap) {
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 Map strategyMap = new ConcurrentHashMap<>();
static {
// 上述模版模式的实现类
strategyMap.put("business1", Xxxx1);
strategyMap.put("business2", Xxxx2);
strategyMap.put("business3", Xxxx3);
}
// 初始化
public OptStrategyContext(Map strategyMap) {
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中的流程步骤,可以抽象出固定的流程为:请求入参处理-》业务逻辑处理-》结果返回处理。
其中业务逻辑处理可以选定为2.2中介绍的通过策略模式选择业务扩展的子类,来处里业务部分;请求入参和结果返回处理部分可以设置为扩展点,供子类扩展。具体伪代码如下:
// 抽象类固定业务流程 预留扩展点 适配多端型多场景
public abstract class AbstractSceneAdapter {
T doXxx(Object context) {
// 节点1
doRequestFilter(context);
// 节点2
getBusinessService(context).doBusiness(context);
// 节点3
return doResultWrap(context);
}
// 扩展点1
protected abstract Result doRequestFilter(Object context);
// 扩展点2
protected abstract Result doBusiness(Object context);
// 扩展点3
protected abstract Result doResultWrap(Object context);
// 业务逻辑处理子类
protected abstract BusinessService getBusinessService(Object context);
}
// 策略处理 根据不同端型场景选择合适的子类
public class SceneAdapterViewService {
private Map strategyMap = new ConcurrentHashMap<>();
static {
// 上述模版模式的实现类
strategyMap.put("scene1", Xxxx1);
strategyMap.put("scene2", Xxxx2);
strategyMap.put("scene3", Xxxx3);
}
// 初始化
public SceneAdapterViewService(Map strategyMap) {
this.strategyMap.clear();
this.strategyMap.putAll(strategyMap);
}
public Result doXxxx(Object context) {
return strategyMap.get(scene).doXxxx(context);
}
}
2.3.1 棒棒糖模式适配
通过模版模式来适配时会有一个小问题,当需要有多个请求入参处理器或者多个结果包装器的时候需要在模版里增加处理节点,但其实这些节点是有共性的可抽象出来的。因此可以针对入参处理器和结果包装器定义单独的接口,需要多个处理器时同时实现接口进行处理。然后这些实现类打包放在单独的类中依次执行即可。当然其中的业务处理部分也可以定义接口动态实现。伪代码如下:
// 入参处理器
public interface IRequestFilter<> {
void doFilter(T t);
}
// 结果包装器
public interface IResultWrapper<R, T> {
Result doWrap(Result res);
}
public class SceneAdapterViewService implements InitializingBean {
private List filters;
private List wrappers;
private Map strategyMap = new ConcurrentHashMap<>();
// 请求过滤器实现类
"filter1") (
private IRequestFilter filter1;
"filter2") (
private IRequestFilter filter2;
// 结果处理器实现类
"wrapper1") (
private IResultWrapper wrapper1;
// 业务处理实现类
"scene1") (
private SceneAdapter scene1;
"scene2") (
private SceneAdapter scene2;
"scene3") (
private SceneAdapter scene3;
// 主方法
publice Result sceneAdapte(Object context) {
// 请求入参过滤 异常时返回
for(int i = 0; i
try {
filters.get(i).doFilter(context)
} catch {
return null;
}
}
// 策略模式执行业务逻辑,执行是按照模版模式
Result res = strategyMap.get(scene).doXxxx(context);
Result result = res;
// 过滤处理,包括树结构改变,数据字段裁剪等
for(int i = 0; i
try {
result = wrappers.get(i).doWrap(result)
} catch {
return res;
}
}
return result;
}
// 初始化各个节点值
public void afterPropertiesSet() throws Exception {
// 入参过滤器 可多个
filters.add(filter1);
filters.add(filter2);
// 结果处理器 可多个
wrappers.add(wrapper1);
// 业务处理部分
strategyMap.put("scene1", Xxxx1);
strategyMap.put("scene2", Xxxx2);
strategyMap.put("scene3", Xxxx3);
}
}
基于上述两种设计模式来适配时我们的接口又该如何设计,是设计面向通用的业务层接口还是面向定制化的业务接口,两种方式各有优缺点:
对于接口提供者来说肯定不希望频繁改动代码发布代码,但是又希望能够在业务承接过程中能够高效适配多端型多场景,因此这里总结了下接口设计原则:
1、对于越底层的接口应该越通用,例如HSF接口、领域服务、中间件提供的接口;
2、对于越上层的接口应该越定制化,例如对于不同的UI适配、不同的场景适配等;
3、对于业务领域内的接口应该通用化,例如直播业务域的分发领域、互动领域内的接口尽可能的通用化;
在承接业务过程中会面临频繁包接口、一个view层的数据模型充满了小100个属性,系统的扩展性遇到瓶颈,这些问题除了通过平台化配置化的能力来解决,但是回归到代码本身我们任然可以通过抽象的设计模式来解决。
-
基于抽象的理论达到复用、高内聚低耦合,降低系统复杂度的目标,设计模式不只是用在底层能力或中间件中,在业务承接过程中亦有大的功效。 -
千万不要为了用设计模式而刻意使用设计模式,带来的效果适得其反,在选择设计模式时也要三思,落地后再改动成本将会巨大。 -
在前台业务开发中,需要划分主各个业务领域,在领域中抽象出该业务的处理流程,基于流程可设计相关的扩展和编排能力,方式有很多种,包括SPI、设计模式、DSL等,本文主要通过模版模式和棒棒糖模式来解决问题。 -
接口设计应该按照越底层越通用,越上层越定制化的原则进行设计,当然在业务域内的接口应尽可能的通用话。
阿里云开发者社区,千万开发者的选择
阿里云开发者社区,百万精品技术内容、千节免费系统课程、丰富的体验场景、活跃的社群活动、行业专家分享交流,欢迎点击【阅读原文】加入我们。
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=12989,转载请注明出处。
评论0