开源项目中常有以 Context 命名的类,如 Spring 的 ApplicationContext、Dubbo 的 RpcContext、Netty 的 ChannelHandlerContext 等等。这些类的作用在于传递流程中所用到的各种数据,故称上下文。除了用来满足功能外,上下文类其实背后还体现了一种设计模式,这种设计模式可以帮助我们提升系统的可扩展性。

曾遇到很多系统,业务流程中的某一步因业务原因需要增加功能,而这个功能所需的参数是原来所没有的。因此,实现这个功能的方法首先要增加新参数,而这个参数的生成可能是在很多步之前的一个地方。因此,这个新加了参数的方法调用链上直到参数提供者的每一个环节也都需要增加新参数。如此,一个需求很多地方都需要改动,扩展性可想而知。

Context 模式可以很好地解决这个问题。对于业务核心流程中所用到的主要和次要数据,我们都可以放在 Context 中。当再遇到上述需求时,通常只需直接使用 Context 中的数据即可。即便需要新增加数据,改动点会比不使用 Context 要少很多。

AssignContext 有好处有坏处。   好处是穿插整个生命周期,做到极大化的扩展。  坏处是破坏了面向对象的职责单一的原则,因为AssignContext 拥有了很多数据,本应该是各个对象做的事情,都倾斜到AssignContext 去做了。

/*** 抽象的执行上下文*/
public abstract class BaseContext {//附加的参数protected Map<String, Object> attachParam;//表对应areaIdprotected String areaId;//数据仓库辅助protected RepositorySupport repositorySupport;//主表名protected String mainTable;//赋值字段protected AssignField assignField;//需要累加的计算区域(子区域)protected List<DirectCalculateArea> directCalAreaList;//监听器传入的DATAprotected ThreadLocal<IBOData> iBOData;//赋值区域数据集合protected ThreadLocal<List<IBORowData>> assignAreaData;//当前赋值区域数据protected ThreadLocal<IBORowData> curAssignAreaData;//当前计算区域字段protected ThreadLocal<List<IBOValueObject>> curDirectCalculateField;//当前计算区域protected ThreadLocal<DirectCalculateArea> curDirectCalculateArea;public BaseContext() {repositorySupport = RepositorySupportFactory.getRepositorySupport();attachParam = new HashMap<>();directCalAreaList = new ArrayList<>();iBOData = new ThreadLocal<>();assignAreaData = new ThreadLocal<>();curAssignAreaData = new ThreadLocal<>();curDirectCalculateField = new ThreadLocal<>();curDirectCalculateArea = new ThreadLocal<>();}//----------------------------------------------本地线程数据的贫血方法--------------------------------------------------public IBOData getIBOData() {return this.iBOData.get();}public void setIBOData(IBOData value) {this.iBOData.set(value);}public List<IBORowData> getAssignAreaData() {return this.assignAreaData.get();}public void setAssignAreaData(List<IBORowData> list) {this.assignAreaData.set(list);}public IBORowData getCurAssignAreaData() {return this.curAssignAreaData.get();}public void setCurAssignAreaData(IBORowData value) {this.curAssignAreaData.set(value);}public List<IBOValueObject> getCurDirectCalculateField() {return curDirectCalculateField.get();}public void setCurDirectCalculateField(List<IBOValueObject> curDirectCalculateField) {this.curDirectCalculateField.set(curDirectCalculateField);}public DirectCalculateArea getCurDirectCalculateArea() {return curDirectCalculateArea.get();}public void setCurDirectCalculateArea(DirectCalculateArea value) {this.curDirectCalculateArea.set(value);}/*** 清理本线程数据,防止内存泄漏和线程复用的bug*/public void clear() {this.iBOData.remove();this.assignAreaData.remove();this.curAssignAreaData.remove();this.curDirectCalculateField.remove();this.curDirectCalculateArea.remove();}//------------------------------------------------业务逻辑------------------------------------------------------------public void assign(IBOData boData) {try {//设置本线程的boDatathis.setIBOData(boData);//获取赋值区域List<IBORowData> list = this.getRepositorySupport().getRowData(boData, this.getAreaId());//设置本线程的赋值区域数据this.setAssignAreaData(list);//赋值区域为空if (list == null || list.size() == 0) {return;}//遍历赋值区域的数据行for (int i = 0; i < list.size(); i++) {IBORowData rowData = list.get(i);//设置本线程的当前赋值区域数据this.setCurAssignAreaData(rowData);//根据当前行,获取计算区域的值CalculateResult calculateResult = cal();//计算值为空if (calculateResult == null) {continue;}calculateResult.setAssignContext(this);//给赋值字段值赋值this.getAssignField().assign(rowData, calculateResult);}} catch (Exception e) {throw new RuleAssignException(e.getMessage());} finally {//清除本线程变量this.clear();}}/*** 抽象的获取计算结果* @return*/protected abstract CalculateResult cal();//-----------------------------------------------贫血方法------------------------------------------------------------public AssignField getAssignField() {return assignField;}public BaseContext setAssignField(AssignField assignField) {this.assignField = assignField;return this;}public BaseContext setAreaId(String areaId) {this.areaId = areaId;return this;}public BaseContext setMainTable(String mainTable) {this.mainTable = mainTable;return this;}public String getAreaId() {return areaId;}public RepositorySupport getRepositorySupport() {return repositorySupport;}public String getMainTable() {return mainTable;}public void addAttachParam(String key, Object param) {this.attachParam.putIfAbsent(key, param);}public Object getAttachParam(String key) {return this.attachParam.get(key);}public List<DirectCalculateArea> getDirectCalAreaList() {return directCalAreaList;}public void addDirectCalculateArea(DirectCalculateArea directCalculateArea) {this.directCalAreaList.add(directCalculateArea);}}
/*** 直接赋值的执行上下文*/
public class AssignContext extends BaseContext {//计算子区域策略protected CalculateFieldStrategy calculateFieldStrategy;//计算子区域的开放接口protected CalculateFieldHandler calculateFieldHandler;public AssignContext() {super();}//-----------------------------------------------业务方法------------------------------------------------------------/*** 获取计算区域的数值* @return*/protected CalculateResult cal() {List<IBOValueObject> iboValueObjects = new ArrayList<>();List<DirectCalculateArea>  directCalAreaList = this.getDirectCalAreaList();//遍历计算区域for (int i = 0; i < directCalAreaList.size(); i++) {DirectCalculateArea directCalculateArea = directCalAreaList.get(i);//设置本线程的当前计算区域this.setCurDirectCalculateArea(directCalculateArea);//当前计算区域的字段值集合iboValueObjects.addAll(directCalculateArea.getCalculateAreaStrategy().getFieldData(this));}//设置本线程的当前计算区域的字段值集合setCurDirectCalculateField(iboValueObjects);//计算结果if (this.getCalculateFieldStrategy() != null) {return this.getCalculateFieldStrategy().action(this);} else if (this.getCalculateFieldHandler() != null) {return this.getCalculateFieldHandler().action(this);}return null;}//-----------------------------------------------添加计算区域的方法----------------------------------------------------/*** 添加计算区域* @param directCalArea*/public void addCalArea(DirectCalculateArea directCalArea) {getDirectCalAreaList().add(directCalArea);}public void addCalAreaById(String areaId, String fieldCode) {addCalArea(new DirectCalculateArea(areaId, fieldCode));}public void addCalAreaById(String areaId, String fieldCode, CalculateAreaStrategy calculateAreaStrategy) {addCalArea(new DirectCalculateArea(areaId, fieldCode).setCalculateAreaStrategy(calculateAreaStrategy));}public void addCalAreaByCode(String mainTable, String areaCode,  String fieldCode) {if (this.mainTable == null) {this.mainTable = mainTable;} else {if (this.mainTable != mainTable) {throw new RuleAssignException("mainTable is not equal, can't add calarea");}}addCalAreaById(this.getRepositorySupport().getBoAreaIdByMainTableAndAreaCode(mainTable, areaCode), fieldCode);}public void addCalAreaByCode(String mainTable, String areaCode, String fieldCode, CalculateAreaStrategy calculateAreaStrategy) {if (this.mainTable == null) {this.mainTable = mainTable;} else {if (this.mainTable != mainTable) {throw new RuleAssignException("mainTable is not equal, can't add calarea");}}addCalAreaById(this.getRepositorySupport().getBoAreaIdByMainTableAndAreaCode(mainTable, areaCode), fieldCode, calculateAreaStrategy);}public void addCalAreaByCode(String areaCode, String fieldCode) {if (this.mainTable == null) {throw new RuleAssignException("mainTable is null, can't add calarea");}addCalAreaByCode(this.mainTable, areaCode, fieldCode);}public void addCalAreaByCode(String areaCode, String fieldCode, CalculateAreaStrategy calculateAreaStrategy) {if (this.mainTable == null) {throw new RuleAssignException("mainTable is null, can't add calarea");}addCalAreaByCode(this.mainTable, areaCode, fieldCode, calculateAreaStrategy);}//-------------------------------------------------贫血方法-----------------------------------------------------------public AssignContext setAreaId(String areaId) {this.areaId = areaId;return this;}public AssignContext setMainTable(String mainTable) {this.mainTable = mainTable;return this;}public BaseContext setCalculateFieldStrategy(CalculateFieldStrategy calculateFieldStrategy) {this.calculateFieldStrategy = calculateFieldStrategy;return this;}public BaseContext setCalculateFieldHandler(CalculateFieldHandler calculateFieldHandler) {this.calculateFieldHandler = calculateFieldHandler;return this;}public CalculateFieldStrategy getCalculateFieldStrategy() {return calculateFieldStrategy;}public CalculateFieldHandler getCalculateFieldHandler() {return calculateFieldHandler;}
}
/*** 表达式赋值的执行上下文*/
public class ExpressionContext extends BaseContext {//整个表达式private String expression;//=右侧的表达式private String calAreaString;//=右侧的占位符表达式private String calAreaTakePlaceString;public ExpressionContext(String expression) {super();this.expression = expression;}//-----------------------------------------------业务方法------------------------------------------------------------protected CalculateResult cal() {List<DirectCalculateArea>  directCalAreaList = this.getDirectCalAreaList();List<CalculateResult> calculateResults = new ArrayList<>();for (int i = 0; i < directCalAreaList.size(); i++) {List<IBOValueObject> iboValueObjects = new ArrayList<>();//遍历计算区域ExpressionCalculateArea directCalculateArea = (ExpressionCalculateArea)directCalAreaList.get(i);//设置本线程的当前计算区域this.setCurDirectCalculateArea(directCalculateArea);//当前计算区域的字段值集合iboValueObjects.addAll(directCalculateArea.getCalculateAreaStrategy().getFieldData(this));//设置本线程的当前计算区域的字段值集合setCurDirectCalculateField(iboValueObjects);CalculateResult calculateResult = directCalculateArea.getCalculateFieldStrategy().action(this);if (calculateResult != null) {calculateResults.add(calculateResult);} else {//没有获取到值,放个占位符吧calculateResults.add(new CalculateResult(null));}}//通过计算器计算结果return ExpressionCalculator.getInstance().cal(this.calAreaTakePlaceString, calculateResults);}//-----------------------------------------------贫血方法------------------------------------------------------------public String getCalAreaString() {return calAreaString;}public void setCalAreaString(String calAreaString) {this.calAreaString = calAreaString;}public String getCalAreaTakePlaceString() {return calAreaTakePlaceString;}public void setCalAreaTakePlaceString(String calAreaTakePlaceString) {this.calAreaTakePlaceString = calAreaTakePlaceString;}public String getExpression() {return expression;}}

Context上下文穿插方式,不是设计模式,但胜于设计模式。相关推荐

  1. React的组件中的传值,及context上下文的使用

    React的组件之间互相传值 父子组件传值 兄弟组件传值 上下文context 父子组件传值 react 中父组件可以将数据作为子组件的属性进行传值,子组件通过 props 属性接收值. 父组件可以监 ...

  2. Android之让代码跑在主线程(无context上下文)的封装

    1.问题 有一段代码需要跑在主线程里面,但是没有context上下文,一开始直接想到runOnUiThread,好像不行 runOnUiThread(new Runnable(){public voi ...

  3. ASP.net MVC Mock Context(上下文)

    ASP.net MVC Mock Context(上下文) Code var fakeContext = new FakeControllerContext(controller, new NameV ...

  4. 设计模式示例_状态设计模式示例

    设计模式示例 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式如此重要的原因 ...

  5. grasp设计模式应用场景_设计模式 GRASP GoF

    借用公开课 Justice 中的话,了解设计模式不一定能让我们解决软件设计与开发中的问题,但能让我们在遇到问题时,思考的方式不至鲁莽与茫然. 五大设计原则 面向对象软件设计具有五大基本原则(首字母缩写 ...

  6. 设计模式面试题(设计模式速成版)

    文章目录 说明 名词解释 UML基础 面向对象编程中,都有哪些设计原则 开闭原则 里氏替换原则(Liskov Substitution Principle) 依赖转置(依赖倒置)原则 单一职责原则 接 ...

  7. 大话设计模式、UML、设计模式Java版完全总结

    此篇博客为阅读大话设计模式后的笔记记录( 读完本文>≈读完<大话设计模式> ),注意是笔记形式,优先适合于对设计模式有一定了解的读者,希望短时间快速温习的读者,同时也对所有设计模式添 ...

  8. 设计模式学习1:设计模式简述和设计模式原则

    设计模式简述 什么是设计模式? 软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案. 设计模式的目的: 代码高可用(相同作用的代码能重复 ...

  9. [Head First设计模式]餐馆中的设计模式——命令模式

    系列文章 [Head First设计模式]山西面馆中的设计模式--装饰者模式 [Head First设计模式]山西面馆中的设计模式--观察者模式 [Head First设计模式]山西面馆中的设计模式- ...

最新文章

  1. python3.7安装numpy模块-Python3.7模块numpy
  2. Zabbix配置详解
  3. springboot导包显示不存在_(一)SpringBoot搭建基本后端应用
  4. Java中的enum详细解析------Java enum 枚举还可以这么用
  5. c#打开文件程序闪退_C#调用易语言dll第二次就闪退
  6. C++中sizeof详解
  7. DenseNet翻译:Densely Connected Convolutional Networks
  8. 数据库内获取准确的当前时间
  9. 不限时长的电脑录屏软件的软件有哪些?良心安利这3款!
  10. ECharts中国区域地图
  11. ANSYS CFD网格划分笔记1
  12. 02组团队项目-Alpha冲刺-3/6
  13. Linux —— 时间问题(localtime和gmtime)
  14. shopee虾皮面试题汇总-C++后端
  15. 数据可视化UI设计素材资源文件sketch大屏可视化数据展示
  16. sql的null对求和的影响
  17. 如何评价一个好系统?
  18. JavaScript专题(一)变量提升与预编译,一起去发现Js华丽的暗箱操作
  19. 无需注册试用ChatGPT
  20. properties的配置信息出现\u7684\u6570\u636e\u5e93\u914d\u7f6e

热门文章

  1. antd vue表单验证_ant design vue框架中自定义表单或单个表单框验证
  2. Cisco Viptela SD-WAN 基本部署
  3. go语言读取json文件的方法
  4. 【渝粤教育】21秋期末考试互联网金融10139k2
  5. ttl mysql_TTL 生存时间
  6. 入坑就对了!如何用机器学习甄别真假美猴王?
  7. 学习笔记(2):8小时学会HTML网页开发-网页布局之切切豆腐
  8. skywalking和jpa冲突
  9. spring实战学习(三)配置方式
  10. linux终端如何连接wifi,如何在 Linux 终端中连接使用 WiFi?